feat(inbound): custom receiving domains + catch-all addresses - #14
Conversation
Extends inbound support with the phase-2 capabilities now on the API: claim a custom domain to receive on (alongside the shared receiving domain), and provision catch-all addresses. Covers both the sync and async clients. - client.inbound.domains — list(), create(domain, ...), delete(id) on both Inbound and AsyncInbound. create() returns the DNS records to publish; an existing-MX conflict surfaces as a 409 SenderKitAPIError so callers can confirm before redirecting mail. - inbound.addresses.create() gains domain_id and livemode; local_part "*" provisions a catch-all. - New models: InboundDomain, InboundDnsRecord. Tests: ruff, mypy, and pytest all pass.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
CI status: the red checks are It's pre-existing on the base branch: this PR is stacked on the inbound base branch, whose CI fails identically, so it needs to clear there. This phase-2 diff itself passes Generated by Claude Code |
CI installs the dev extra with a floating `ruff>=0.5`, so it picks up ruff 0.16, which formats Python code blocks inside Markdown by default. That makes `ruff format --check .` reformat README.md and fail, even though the pinned ruff-pre-commit hook (0.15.17) and local runs are clean. Pin `ruff==0.15.17` in the dev extra so CI matches the pre-commit hook and the lint gate is deterministic. No source changes.
|
Update — root-caused and fixed. The red Fix: pinned Generated by Claude Code |
…essages) Adds async-client tests for the new inbound domains methods and the async address-create params, plus the pre-existing async address/message paths that had no coverage. Raises patch coverage above the project target.
Summary
Follows up the base inbound support with the phase-2 capabilities now available
on the API, on both the sync and async clients:
inbound.acme.com) in addition to the shared receiving domain. Claiming adomain returns the DNS records to publish; it verifies once they're live.
"*"local part receives every address no exactaddress claims.
livemodeand adomain_idto target acustom domain.
Changes
client.inbound.domains—list(),create(domain, ...),delete(id)onboth
InboundandAsyncInbound.create()returns the DNS records topublish; a domain that already routes mail elsewhere raises a
409SenderKitAPIError(existing_mx) so a caller can confirm before redirecting.inbound.addresses.create()gainsdomain_idandlivemode;local_part="*"provisions a catch-all.
InboundDomain,InboundDnsRecord.Checklist
ruff check .passesruff format .appliedmypy srcpassespytestpasses (new behavior is covered by tests)This mirrors the matching change in the TypeScript and PHP SDKs so all three
stay in sync.
Generated by Claude Code