LLMs can draft text. MultiMail gives them an actual inbox, approval controls, thread awareness, and delivery guarantees — the infrastructure layer real agents need.
Getting an LLM to compose an email is straightforward. Making that agent reliable in production is not. You need inbox access with proper authentication, a way to queue outbound messages for human review before they send, reply threading so responses land in the right conversation, and an audit trail when something goes wrong. Most developers wire these pieces together from scratch — SMTP credentials, a polling loop, a webhook handler, a queue — and end up with brittle glue code that breaks the first time an approval is missed or a reply lands in the wrong thread.
MultiMail is purpose-built email infrastructure for AI agents. You connect once via MCP or REST API, configure an oversight mode that matches your trust level, and get primitives for the full email lifecycle: check_inbox, read_email, get_thread, draft_reply, decide_email, send_email, and list_pending. The gated_send mode lets your agent read and draft autonomously while queuing every outbound message for human approval before delivery — a practical default for new agents that haven't yet earned full send permissions.
Create a mailbox at your own domain or use a @multimail.dev address. Your API key (mm_live_... or mm_test_...) authenticates all requests. Set the oversight mode to gated_send so the agent can read and draft without sending anything unsupervised.
Add MultiMail to your agent's MCP config to expose all 50 tools directly to your LLM runtime, or call the REST API at https://api.multimail.dev with a Bearer token. Both surfaces expose the same primitives: check_inbox, read_email, get_thread, send_email, reply_email, decide_email, and list_pending.
The agent calls check_inbox to discover new messages, then read_email to retrieve full content, and get_thread to load prior conversation history. Thread context is essential — agents that reply without it produce responses that ignore what was already said.
With thread context in hand, the agent drafts a reply and calls reply_email. In gated_send mode the message is queued rather than sent immediately. The human reviewer sees the full draft via the approval webhook or the list_pending endpoint and can approve or reject.
After approval, MultiMail delivers the message and fires a delivery webhook. The agent can poll or listen for bounce events, open tracking, and reply-back notifications to decide its next action — closing the loop without manual intervention.
{
"mcpServers": {
"multimail": {
"command": "npx",
"args": ["-y", "@multimail/mcp-server"],
"env": {
"MULTIMAIL_API_KEY": "$MULTIMAIL_API_KEY"
}
}
}
}Add MultiMail to your MCP client config. This exposes all 50 tools — check_inbox, read_email, reply_email, decide_email, and more — directly to the LLM runtime.
import httpx
BASE = "https://api.multimail.dev"
HEADERS = {"Authorization": "Bearer $MULTIMAIL_API_KEY"}
"cm"># Find unread messages
inbox = httpx.get(f"{BASE}/check_inbox", headers=HEADERS,
params={"mailbox": "[email protected]", "unread_only": True}).json()
for msg in inbox["messages"]:
"cm"># Load full email
email = httpx.get(f"{BASE}/read_email", headers=HEADERS,
params={"email_id": msg["id"]}).json()
"cm"># Load thread history for context
thread = httpx.get(f"{BASE}/get_thread", headers=HEADERS,
params={"thread_id": email["thread_id"]}).json()
print(f"Thread has {len(thread[&"cm">#039;messages'])} prior messages")
print(f"Subject: {email[&"cm">#039;subject']}")
print(f"From: {email[&"cm">#039;from']}")Poll for new messages, retrieve the full email body, and load thread history before drafting a response.
import httpx
BASE = "https://api.multimail.dev"
HEADERS = {"Authorization": "Bearer $MULTIMAIL_API_KEY"}
"cm"># Draft a reply — queued for approval in gated_send mode
reply = httpx.post(f"{BASE}/reply_email", headers=HEADERS, json={
"email_id": "em_01j9k2x8p3q",
"body": "Hi Priya, I reviewed your request and prepared the next steps for connecting your agent to our workflow. Here is what I recommend...",
"from": "[email protected]"
}).json()
print(f"Queued: {reply[&"cm">#039;message_id']}, status: {reply['status']}") # status: pending_approval
# Reviewer approves via API
decision = httpx.post(f"{BASE}/decide_email", headers=HEADERS, json={
"message_id": reply["message_id"],
"decision": "approve"
}).json()
print(f"Delivered: {decision[&"cm">#039;delivered_at']}")In gated_send mode, reply_email queues the message rather than sending immediately. Use list_pending to inspect the queue and decide_email to approve or reject.
from multimail_sdk import MultiMailClient
client = MultiMailClient(api_key="$MULTIMAIL_API_KEY")
def run_agent_cycle(mailbox: str):
inbox = client.check_inbox(mailbox=mailbox, unread_only=True)
for msg in inbox.messages:
email = client.read_email(email_id=msg.id)
thread = client.get_thread(thread_id=email.thread_id)
"cm"># Pass thread history to your LLM here
draft = your_llm_draft(email=email, thread=thread)
"cm"># Queue for approval (gated_send mode)
result = client.reply_email(
email_id=email.id,
body=draft,
from_address=mailbox
)
print(f"Queued {result.message_id} — awaiting approval")
run_agent_cycle("[email protected]")The multimail-sdk wraps the REST API with typed methods. This shows a minimal read-draft-queue loop suitable for a background agent.
MultiMail handles delivery, bounce handling, DKIM signing, and inbound parsing. Your agent calls check_inbox and read_email — no SMTP credentials, no polling loop, no MX record management.
gated_send mode queues every outbound message before delivery. You get list_pending and decide_email endpoints, plus webhooks — no separate approval service to build and maintain.
get_thread returns the full conversation history in a single call. Replies land in the correct thread with proper In-Reply-To headers, so responses appear correctly in every email client your recipients use.
Every read, draft, approval, and send is logged with agent identity headers. When a message causes a problem, you can trace exactly what the agent saw and when it acted.
Start at gated_send, move to monitored once you trust the agent's judgment, and eventually to autonomous. The oversight mode is a single config change — no code rewrites, no new infrastructure.
Whether you use an MCP client like Claude Desktop or call the REST API directly, you get the same 50 tools with the same behavior. You can prototype in an MCP client and deploy via REST without rewriting logic.
Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.