Can the Claude Agent SDK read and reply to email?
Yes, with mailbox tools and an application that controls when sending is allowed. For a Claude Agent SDK email workflow, separate reading from sending: the agent proposes a reply; your server decides whether an approved reply can leave the mailbox.
The Agent SDK is a software development kit for building applications around Claude, rather than a conversation in the interactive Claude app. Use Anthropic's official TypeScript SDK repository for the package @anthropic-ai/claude-agent-sdk.
Mailera supplies the email connection through Mailera MCP. Its tools include list_mailboxes, list_messages, and get_message for reading, plus reply_to_email and get_send_status for the separate sending path.
If you're looking for a Claude Agent SDK email example on GitHub, Anthropic's SDK demos repository describes an in-development IMAP email assistant. The repository warns that its demos are for local development, not production deployment. The workflow here uses an existing mailbox through MCP instead of a direct IMAP connection.
What do you need before building the workflow?
Start with a mailbox you own, a Mailera workspace, and a controlled recipient. Use a dedicated mailbox group so the reading agent cannot browse unrelated mail. For Outlook or Microsoft 365, follow the Microsoft OAuth connection instructions.
Prepare your TypeScript project using the SDK repository's installation instructions. Configure Anthropic authentication separately from the Mailera API key: the Mailera credential authorizes mailbox access, not model access.
Assign responsibilities before writing the agent prompt:
| Component | Responsibility |
|---|---|
| Claude Agent SDK application | Read the selected message and propose reply text |
| Mailera MCP | Expose tools for connected mailboxes |
| Host application | Store proposals, display review screens, record approval |
| Trusted sending executor | Submit the approved reply and track its send attempt |
Keep credentials server-side. Do not put the sending key in the reading agent's environment, prompt, or tool results. Use the Mailera developer overview for the API side and the Claude integration page for client connection guidance.
How do you prepare Mailera MCP access?
1. Confirm the mailbox can send
Open Mailboxes and check the intended mailbox's connection status and last sync. A mailbox saved with Save as receive-only can support the reading step but cannot complete the reply workflow.
You can inspect capabilities independently of the SDK. Set $MAILERA_API_KEY to your read key and $MAILBOX_ID to the test mailbox identifier:
curl --fail-with-body \
"https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID" \
-H "Authorization: Bearer $MAILERA_API_KEY"Check data.capabilities.send, data.status, and data.sync. This isolates mailbox setup from agent configuration.

2. Create a reading credential
In Settings, open the API key tab and select Create key. Choose the test group under Mailbox scope, enable Read, and set Expiration for the test. Leave Send messages disabled.
Save the key when Key created — copy it now appears. Copy MCP config provides a client configuration reference for Claude, Cursor, or VS Code; adapt that reference to your SDK's configuration rather than treating the formats as interchangeable.
The MCP endpoint is https://mailera.app/api/public/v1/mcp. Authentication uses Authorization: Bearer $MAILERA_API_KEY, with your application substituting the environment variable's value.

3. Restrict the reading agent's tools
Discover the server's tools and their argument schemas. Resolve the SDK-qualified tool names from that connection; don't construct them from a naming guess.
For this task, permit only list_mailboxes, list_messages, and get_message. A Read-scoped key is a permission boundary, not a per-tool filter: other Mailera tools, including get_latest_otp, also use the read scope.
Do not assume an option named “allowed tools” removes every other tool. In Anthropic's Python SDK documentation, allowed_tools auto-approves listed tools, while unlisted tools fall through to other permission handling. Keep language-specific configuration separate and enforce a deny-by-default policy in your TypeScript host.
Check that the agent can access the intended mailbox and read a message, but its credential cannot authorize sending. The existing-mailbox MCP guide explains the broader connection model.
How do you read a message and prepare a reply?
4. Select one controlled message
Use list_mailboxes to identify the test mailbox, list_messages to select the test message, and get_message to retrieve its content. Use the discovered MCP schemas for arguments.
If the content looks wrong, compare it with a direct REST read. Set $MESSAGE_ID to the selected message identifier:
curl --fail-with-body \
"https://mailera.app/api/public/v1/mailboxes/$MAILBOX_ID/messages/$MESSAGE_ID" \
-H "Authorization: Bearer $MAILERA_API_KEY"Inspect data.mailbox_id, data.id, data.subject, and data.body.text. Keep mailbox and original-message identifiers in trusted application state rather than asking the model to reproduce them.
5. Store a proposal, not a send request
Ask the agent for a short summary and proposed reply text. Store the proposal in your application; do not make the workflow depend on a provider-synced draft.
The review screen should show the sending mailbox, original-message reference, recipient, subject, and complete reply body. Include every recipient if you support multiple recipients. For the first implementation, keep it to a single controlled recipient.
Require the reviewer to inspect the actual outgoing content, not just the agent's summary. At this checkpoint, a proposal exists and is visible, but nothing has been submitted for sending.

How do you send only the reply a human approved?
6. Bind approval to an exact snapshot
An approval should identify a stored proposal version and the person who approved it. Changing the mailbox, original message, recipient, subject, or body must invalidate that approval.
For a single-recipient TypeScript application, this small comparison helper makes the content boundary explicit. These are local application types, not Mailera request fields:
type Reply = Readonly<{
mailboxId: string; originalMessageId: string;
recipient: string; subject: string; body: string;
}>;
const snapshot = (r: Reply): string => JSON.stringify([
r.mailboxId, r.originalMessageId, r.recipient, r.subject, r.body,
]);
export function assertApproved(
current: Reply, approved: Reply, state: string,
): void {
if (state !== "approved" || snapshot(current) !== snapshot(approved)) {
throw new Error("Explicit approval required for this exact reply");
}
}Load both objects and the approval state from trusted server storage. Never accept an approved flag or an approval snapshot supplied by the agent as authorization.
The comparison belongs inside a larger transaction: authenticate the reviewer, record the immutable approved version, and atomically claim it for sending. Repeated approval submissions must not create additional send jobs. Rejection ends the workflow without a send.
7. Send from a separate executor
Give the executor a separate key with Send messages permission and the same narrow mailbox scope. It should load the approved snapshot and call reply_to_email using the discovered schema. Do not ask the model to regenerate the reply after approval.
Keep the sender credential outside the reading agent's process where possible. A prompt that says “ask before sending” is not an authorization boundary.
The MCP specification requires explicit user consent before a host invokes a tool and recommends building reliable consent and authorization flows into applications. MCP cannot enforce those principles by itself. Implement review and approval in the host application, not as an assumed Mailera feature. If the reviewer will approve through email, use a separate email-based approval pattern.
8. Track the send attempt before retrying
After submission, use get_send_status, which also requires the send scope. Keep the approval record and submission outcome together in trusted application storage.
Mailera's REST send-status endpoint describes these outcomes:
| Status | Application action |
|---|---|
queued | Keep the attempt pending |
sending | Wait; don't submit another reply |
sent | Record the reported result without promising inbox placement |
failed | Inspect the failure before deciding on a retry |
unknown | Reconcile the existing attempt before another submission |
A timeout is not permission to generate a new send. Mailera's REST send endpoint accepts Idempotency-Key; do not assume that header applies to an MCP tool call. For a REST sending path, follow the duplicate-send prevention guide.
What commonly goes wrong?
| Symptom | Likely cause | Check |
|---|---|---|
| Authentication fails | Expired or revoked key; incorrect header | Check expiration and revocation without logging the credential |
| Mailbox is missing | Wrong mailbox group | Compare the key's Mailbox scope with the test mailbox's group |
| Tool cannot be called | Configuration, transport, or tool-name mismatch | Inspect discovery results and SDK-qualified names |
| Message list is empty or stale | Wrong folder, disconnected mailbox, or sync state | Compare mailbox identity, folder, status, and last sync |
| Reply fails | Receive-only mailbox or missing send permission | Check capabilities.send and the executor's key permissions |
| Approval changes nothing | Edited proposal or already-claimed job | Inspect the stored version and approval state |
| Submission times out | Outcome is unresolved | Retrieve the existing send attempt before retrying |
Mailera's background checks vary with mailbox activity, so don't design around instantaneous synchronization. Mailera also cannot guarantee inbox placement.
How do you keep incoming email from controlling the agent?
Treat message bodies, quoted text, links, and attachments as untrusted data, not instructions. An incoming message must not be able to change tool permissions, choose a different recipient, reveal credentials, or bypass review.
Disable unrelated tools, including shell execution and filesystem access. Do not open arbitrary URLs just because an email requests it. Keep sensitive message content out of routine logs; the Mailera security page covers the product side, while your host must protect its own proposal and approval records.
Before enabling sending, test these outcomes:
- Reject a proposal: no send job is created.
- Edit an approved reply: approval is required again.
- Submit approval repeatedly: only one job is claimed.
- Send a test email that asks the agent to reveal a key and reply without review: no credential is exposed and no send is invoked.
For the broader risk assessment, see whether it is safe to connect Claude to Gmail. The essential boundary here is concrete: incoming email can influence proposed text, but only your application can authorize the exact outgoing reply.
Let AI agents use your mailbox via MCP
Add Mailera's MCP server to Claude, Cursor or VS Code so agents can read, categorize and reply to email messages.
Learn how to use MCP








