Skip to content

feat: inbound receiving addresses and received mail - #12

Merged
tuyakhov merged 10 commits into
mainfrom
claude/gallant-einstein-czq95m
Jul 29, 2026
Merged

feat: inbound receiving addresses and received mail#12
tuyakhov merged 10 commits into
mainfrom
claude/gallant-einstein-czq95m

Conversation

@tuyakhov

Copy link
Copy Markdown
Contributor

Summary

Adds support for the inbound email API on both the sync and async clients:
provision addresses on a workspace's shared receiving domain and read the mail
sent to them. Access requires an API key with the inbound scope. Received mail
is surfaced through the existing webhook engine as a message.received event.

  • client.inbound.addresseslist(), create(...), delete(id).
  • client.inbound.messageslist(...), get(id), plus raw(id) and
    attachment(id, index) returning raw bytes.
  • New models: InboundAddress, InboundMessage, InboundMessageSummary,
    InboundAttachment, InboundBytes.
  • README gains an Inbound section.

This mirrors the matching change in the TypeScript and PHP SDKs so all three stay
in sync.

Related issues

Checklist

  • ruff check . passes
  • ruff format . applied
  • mypy src passes
  • pytest passes (new behavior is covered by tests)
  • PR title / commits follow Conventional Commits (drives versioning & changelog)
  • Docs / docstrings updated if the public API changed

Generated by Claude Code

Mirrors the TypeScript SDK's new `inbound` resource area on both the sync and
async clients:

- `client.inbound.addresses` — list / create / delete addresses on the
  workspace's shared receiving domain.
- `client.inbound.messages` — list / get received messages, plus `raw()` and
  `attachment(index)` returning raw bytes.
- New models: InboundAddress, InboundMessage(+Summary), InboundAttachment,
  InboundBytes.

Requires an API key with the `inbound` scope. Tests cover the address CRUD and
message read/raw/attachment paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Ws2dq33N1tvwrWakzqgxL
Comment thread tests/test_inbound.py Fixed
@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.21429% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/senderkit/resources/inbound.py 97.10% 1 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

claude and others added 7 commits July 28, 2026 21:16
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.
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.
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.
…-pin

ci(ruff): pin ruff below 0.16 to match the pinned pre-commit hook
…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.
feat(inbound): custom receiving domains + catch-all addresses
Comment thread tests/test_inbound.py Fixed
Comment thread tests/test_inbound.py Fixed
Comment thread tests/test_inbound.py Fixed
claude and others added 2 commits July 29, 2026 12:10
CodeQL flags `assert <call> is True` because the call is skipped when asserts
are disabled (python -O). Assign each delete() result to a local first, then
assert on the value. Resolves the four "assert statement has a side-effect"
code-scanning alerts on tests/test_inbound.py. No behavior change.
…assert

test(inbound): resolve CodeQL "assert has a side-effect" alerts
@tuyakhov
tuyakhov merged commit a2be26d into main Jul 29, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants