Generic email APIs weren't designed for agents. MultiMail provides cryptographically signed agent identity, graduated oversight controls, and compliance built in — not bolted on.
When an AI agent sends email through a generic SMTP relay or transactional API, three things are missing: recipients have no way to verify the message came from an agent rather than a human, your organization has no mechanism to review or gate what the agent sends, and you have no audit trail that satisfies EU AI Act Article 50 disclosure requirements. These aren't edge cases — they're the default failure mode when you wire an LLM to a generic email API.
MultiMail is a purpose-built email API for AI agents. Every sent message carries a cryptographic signature identifying the sending agent. Oversight mode controls whether sends go immediately or wait for human approval. The full audit trail — what the agent tried to send, who approved it, and when — is stored automatically. Access via REST API at https://api.multimail.dev, the multimail-sdk Python package, or the 50-tool MCP server that works directly inside Claude Desktop, Cursor, and Windsurf.
POST to /v1/mailboxes to provision a mailbox on your domain or at @multimail.dev. Your API key (mm_live_... for production, mm_test_... for sandbox testing) authenticates every request. Each mailbox is tied to a specific agent_id that gets embedded in outbound message headers for identity verification.
Set oversight_mode on the mailbox. gated_send (the default) lets your agent read autonomously but holds outbound messages in a pending queue until a human approves. gated_all gates reads too. monitored lets the agent act freely while notifying a human. autonomous is available once trust is established. The mode is enforced server-side — the agent cannot override it.
POST to /v1/emails/send to send. GET /v1/inbox to check incoming messages. Under gated_send, a send call returns immediately with status pending and a message_id. The message sits in the approval queue until a human approves it via the dashboard or the /v1/pending/{id}/approve endpoint.
Register a webhook endpoint to receive real-time events: email.approved, email.rejected, email.delivered, email.inbound. Your agent subscribes to these events and continues its workflow once a human approves a draft — no polling required. Webhook payloads are signed with HMAC-SHA256 for verification.
Every send attempt, approval decision, and delivery event is written to an immutable audit trail. CAN-SPAM required headers are validated before delivery — missing unsubscribe links or physical addresses are rejected outright. EU AI Act Article 50 agent disclosure is added automatically to outbound messages when the mailbox carries an agent_id.
curl -X POST https://api.multimail.dev/v1/emails/send \
-H &"cm">#039;Authorization: Bearer $MULTIMAIL_API_KEY' \
-H &"cm">#039;Content-Type: application/json' \
-d &"cm">#039;{
"from": "[email protected]",
"to": "[email protected]",
"subject": "API Integration Test",
"text": "Testing MultiMail API integration. This message was sent by an AI agent.",
"agent_id": "crm-agent-v1"
}&"cm">#039;
"cm"># Response under gated_send oversight:
"cm"># {
"cm"># "message_id": "msg_01HX9K3ZQABCDEF",
"cm"># "status": "pending",
"cm"># "oversight_mode": "gated_send",
"cm"># "approval_url": "https://app.multimail.dev/pending/msg_01HX9K3ZQABCDEF"
"cm"># }A minimal send request showing authentication, required fields, and the pending response returned under gated_send oversight.
from multimail import MultiMailClient
client = MultiMailClient(api_key="$MULTIMAIL_API_KEY")
"cm"># Send — returns immediately with pending status under gated_send
result = client.send_email(
from_address="[email protected]",
to="[email protected]",
subject="API Integration Test",
text="Testing MultiMail API integration.",
agent_id="crm-agent-v1",
)
print(f"Status: {result.status}") "cm"># pending
print(f"Message ID: {result.message_id}") "cm"># msg_01HX9K3ZQABCDEF
"cm"># Inspect what's waiting for approval
pending = client.list_pending()
for msg in pending:
print(f"Awaiting approval: {msg.subject} → {msg.to}")
"cm"># Read incoming messages autonomously (reads are not gated)
messages = client.check_inbox(
mailbox="[email protected]",
limit=10,
)
for msg in messages:
print(f"Received: {msg.subject} from {msg.from_address}")Using multimail-sdk to send a message and inspect the pending queue before the human approval event fires.
import httpx
HEADERS = {
"Authorization": "Bearer $MULTIMAIL_API_KEY",
"Content-Type": "application/json",
}
"cm"># Create mailbox with gated_send (sends queue for approval, reads are autonomous)
response = httpx.post(
"https://api.multimail.dev/v1/mailboxes",
headers=HEADERS,
json={
"address": "[email protected]",
"display_name": "Support Agent",
"oversight_mode": "gated_send",
"agent_id": "support-agent-v2",
},
)
mailbox = response.json()
print(f"Created: {mailbox[&"cm">#039;address']}")
print(f"Oversight: {mailbox[&"cm">#039;oversight_mode']}")
# Later: promote to monitored once trust is established
httpx.patch(
f"https://api.multimail.dev/v1/mailboxes/{mailbox[&"cm">#039;id']}",
headers=HEADERS,
json={"oversight_mode": "monitored"},
)
print("Promoted to monitored — agent now sends autonomously with notifications")Provision a mailbox with gated_send oversight, then promote it to monitored once the agent's output quality is verified.
from flask import Flask, request, jsonify
import hmac, hashlib
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_your_webhook_secret"
@app.route("/webhooks/multimail", methods=["POST"])
def handle_multimail_event():
sig = request.headers.get("X-MultiMail-Signature", "")
body = request.get_data()
expected = hmac.new(
WEBHOOK_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig, f"sha256={expected}"):
return jsonify({"error": "invalid signature"}), 401
event = request.json
if event["type"] == "email.approved":
message_id = event["data"]["message_id"]
resume_agent_workflow(message_id)
elif event["type"] == "email.rejected":
message_id = event["data"]["message_id"]
reason = event["data"].get("rejection_reason", "no reason given")
handle_rejection(message_id, reason)
return jsonify({"received": True})
def resume_agent_workflow(message_id: str):
print(f"Email {message_id} approved and delivered — continuing workflow")
def handle_rejection(message_id: str, reason: str):
print(f"Email {message_id} rejected: {reason}")Receive real-time notifications when a human approves or rejects an agent-drafted email so your workflow can continue without polling.
"cm">// ~/.config/claude/claude_desktop_config.json
{
"mcpServers": {
"multimail": {
"command": "npx",
"args": ["-y", "@multimail/mcp-server"],
"env": {
"MULTIMAIL_API_KEY": "$MULTIMAIL_API_KEY"
}
}
}
}
"cm">// Claude Desktop can then invoke tools directly, for example:
"cm">//
"cm">// Tool: create_mailbox
"cm">// { "address": "[email protected]", "oversight_mode": "gated_send" }
"cm">//
"cm">// Tool: send_email
"cm">// { "from": "[email protected]",
"cm">// "to": "[email protected]",
"cm">// "subject": "API Integration Test",
"cm">// "text": "Testing MultiMail API integration." }
"cm">//
"cm">// Tool: list_pending
"cm">// {} — returns all messages awaiting human approval
"cm">//
"cm">// Tool: check_inbox
"cm">// { "mailbox": "[email protected]", "limit": 20 }Configure the MultiMail MCP server once and Claude Desktop gains access to send_email, check_inbox, list_pending, and 40 other tools natively.
Every email sent through MultiMail carries a signature identifying the sending agent by its agent_id. Recipients and mail infrastructure can verify the message originated from a known AI agent. This satisfies EU AI Act Article 50 requirements for AI-generated content disclosure without any additional instrumentation.
Start with gated_send — your agent reads freely but all outbound messages hold for human review. Promote to monitored once you've validated the agent's judgment on your specific use case, then to autonomous when full trust is established. The mode is enforced server-side and cannot be bypassed by the agent.
Required CAN-SPAM headers — unsubscribe mechanism, physical address, honest From — are validated before delivery. Missing fields are rejected, not silently dropped. EU AI Act disclosure is appended automatically when the mailbox carries an agent_id and the recipient is a natural person.
Beyond REST, MultiMail ships an MCP server with 50 tools covering the full email lifecycle: send_email, reply_email, check_inbox, read_email, get_thread, tag_email, decide_email, manage_contacts, and more. Install once via npx @multimail/mcp-server and any MCP-compatible client gets full email access.
Every send attempt, approval decision, rejection, and delivery event is logged to an append-only audit trail. You can reconstruct exactly what an agent tried to send, who reviewed it, what they decided, and when — which matters when an enterprise customer or regulator asks.
mm_test_... keys validate the full request contract — auth, required fields, compliance checks — but discard the message before delivery. Switch to mm_live_... for real delivery. Both key types hit the same base URL. No separate test environment configuration, no mock servers, no delivery side effects during development.
Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.