Build a Real AI Email Agent, Not a Demo

LLMs can draft text. MultiMail gives them an actual inbox, approval controls, thread awareness, and delivery guarantees — the infrastructure layer real agents need.


Why this matters

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.


How MultiMail solves this

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.

1

Create a mailbox and get your API key

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.

2

Connect via MCP or REST

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.

3

Read the inbox and load thread context

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.

4

Draft a reply and queue for approval

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.

5

Send and track delivery

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.


Implementation

Connect via MCP (Claude Desktop / Cursor)
json
{
  "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.

Read inbox and load thread context
python
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.

Queue a reply for human approval
python
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.

Full agent loop with MultiMail Python SDK
python
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.


What you get

Inbox access without SMTP plumbing

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.

Approval queue built in

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.

Thread-aware reply routing

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.

Audit trail for every action

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.

Graduated trust as the agent matures

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.

MCP and REST on the same primitives

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.


Recommended oversight mode

Recommended
gated_send
New email agents should not send autonomously until their judgment is proven in production. gated_send lets the agent read and draft without restriction — maintaining its ability to respond to inbound messages quickly — while requiring human approval before any message is delivered. This is the right default for a first deployment: it surfaces edge cases the agent handles poorly without letting those cases reach your users' inboxes.

Common questions

Do I need to manage SMTP credentials or MX records?
No. MultiMail handles delivery infrastructure, DKIM signing, bounce processing, and inbound parsing. You authenticate with a Bearer token and call the REST API or use the MCP server — there are no SMTP credentials to rotate or DNS records to configure beyond pointing your domain's MX to MultiMail.
How does gated_send mode work technically?
When your agent calls reply_email or send_email in gated_send mode, the message is stored with status pending_approval instead of being delivered. MultiMail fires an approval webhook to your endpoint. A human reviewer calls decide_email with decision: approve or reject. On approval, MultiMail delivers the message and fires a delivery webhook.
Can the agent read emails it did not receive — for example, a shared inbox?
Yes. You can create mailboxes at your own domain ([email protected] routed through MultiMail) or at @multimail.dev addresses. Any mailbox your API key has access to is readable via check_inbox and read_email. Permissions are scoped per mailbox in your account.
What happens if a message bounces after approval?
MultiMail fires a delivery status webhook with the bounce reason. The agent can listen for this event via your webhook handler or poll the message status endpoint. Bounce details include the SMTP error code and a classification (hard vs. soft), which the agent can use to decide whether to retry or escalate.
How do I prevent the agent from replying to the same email twice?
Read the email's thread_id before replying. get_thread shows every message in the conversation, including pending approvals. Your agent should check whether a pending or sent reply already exists in the thread before drafting a new one. The list_pending endpoint also surfaces queued replies by thread.
Is there a test mode for building without sending real email?
Yes. API keys prefixed mm_test_ operate in sandbox mode. Emails are processed and stored normally — check_inbox, read_email, and get_thread all work — but delivery is simulated. Inbound test messages can be injected via the API. Switch to mm_live_ to go to production.
Can I use MultiMail with LangChain or CrewAI instead of calling the REST API directly?
Yes. MultiMail has framework integrations for LangChain, CrewAI, AutoGen, and Semantic Kernel. Each integration wraps the same REST primitives as tool-callable functions. The MCP server works with any MCP-compatible runtime, including Claude Desktop, Cursor, and Windsurf.

Explore more use cases

The only agent email with a verifiable sender

Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.