Skip to content

feat(python): surface Forward in sync + async SDKs#175

Merged
jiashuoz merged 1 commit into
mainfrom
feat/forward-python-parity
May 28, 2026
Merged

feat(python): surface Forward in sync + async SDKs#175
jiashuoz merged 1 commit into
mainfrom
feat/forward-python-parity

Conversation

@jiashuoz
Copy link
Copy Markdown
Member

Summary

Closes the parity gap from PR #171. TS SDK, CLI, and MCP shipped with Forward; the Python SDK didn't. This adds matching surface to both sync and async variants — every client now exposes Forward.

What's added

Python SDK — api.py / async_client.py (raw HTTP)

  • `forward_message(agent_email, message_id, body: ForwardMessageRequest, idempotency_key=None) → SendEmailResponse`

Python SDK — client.py / async_client.py (high-level)

  • `forward(message_id, to, body=None, html_body=None, cc=None, bcc=None, conversation_id=None, attachments=None, agent_email=None, idempotency_key=None) → SendResult`
  • Builds the `ForwardMessageRequest` from kwargs; same return-type pattern as `reply()` and `send()` (`SendResult` dataclass).
  • Attachments go through the existing `_serialize_attachments` helper (base64-encoded on the wire).

Cross-client parity now

Client Forward
Go API ✅ (#171)
TypeScript SDK ✅ (#171)
MCP server ✅ (#171)
CLI ✅ (#171)
Python SDK (sync) ✅ this PR
Python SDK (async) ✅ this PR

Verification

  • 202 Python tests pass (+5 new — raw POST + Idempotency-Key header threading, sync high-level returns SendResult, attachments + conversation_id round-trip, async smoke test)

Test plan

  • `pytest sdks/python/tests/test_v1_api.py tests/test_v1_client.py tests/test_v1_async_client.py`
  • Manual: forward an inbound from a Python client and confirm Mailpit receives a `Fwd:` message

🤖 Generated with Claude Code

Closes the parity gap from PR #171 (Forward feature). TS SDK, CLI, and
MCP shipped with Forward; the Python SDK didn't. Adds matching surface
to both sync and async variants.

Raw (api.py / async_client.py):
- forward_message(agent_email, message_id, body: ForwardMessageRequest,
  idempotency_key) → SendEmailResponse

High-level (client.py / async_client.py):
- forward(message_id, to, body=None, html_body=None, cc=None, bcc=None,
  conversation_id=None, attachments=None, agent_email=None,
  idempotency_key=None) → SendResult
  Builds the ForwardMessageRequest from kwargs, base64-encodes
  attachments via the existing _serialize_attachments helper, returns
  the SendResult dataclass — same shape callers already use for
  reply() and send().

Tests (+5):
- api.py: POST /forward with Idempotency-Key header threaded through
- client.py: high-level forward() returns SendResult; attachments +
  conversation_id round-trip correctly through the wire
- async_client.py: async high-level forward() smoke test

202 tests pass (was 197).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jiashuoz jiashuoz merged commit 5ab4244 into main May 28, 2026
10 checks passed
@jiashuoz jiashuoz deleted the feat/forward-python-parity branch May 28, 2026 22:42
jiashuoz added a commit that referenced this pull request May 28, 2026
Adds .github/pull_request_template.md as a forcing function against
the parity gap we hit on #171 (Forward shipped to Go/TS/CLI/MCP but
missed Python; needed #175 to close). The template surfaces the full
client matrix (Go, TS SDK, Python SDK sync+async, CLI, MCP) plus
migration safety, generated-types refresh, and a per-surface tests
row.

GitHub auto-fills this on `gh pr create` and the web "New PR" form,
so it's free to author and free to enforce. Rows are individually
deletable for PRs that don't touch the API or any client.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant