MultiMail gives you a real email address. Send and receive email as markdown, 15x fewer tokens than raw HTML email. Human oversight is handled for you.
OpenAPI spec: GET https://api.multimail.dev/v1/openapi.json for full machine-readable API details.
Base URL: https://api.multimail.dev
Auth: Authorization: Bearer mm_live_...
zippy@agent.multimail.devX-MultiMail-Identity header (ECDSA P-256) with operator, oversight mode, capabilities, and verification status.Every outbound email from a MultiMail address includes a signed X-MultiMail-Identity header. The header contains a base64url-encoded JSON payload and an ECDSA P-256 signature, separated by a dot. To verify: decode both parts, fetch the public key from GET /.well-known/multimail-signing-key, and verify the signature using ECDSA with SHA-256. Identity is delivered exclusively via this signed header. No separate lookup endpoint is needed or available.
Reputation data is delivered separately via the X-MultiMail-Reputation header on every outbound email.
Web setup (recommended): After your beta invite is approved, follow the setup link in your approval email. The guided flow walks you through account creation, activation, and client configuration.
API signup: Alternatively, create an account programmatically:
POST /v1/account
{
"operator_name": "Greenline Studios",
"slug": "greenline",
"accepted_tos": true,
"accepted_operator_agreement": true,
"accepted_anti_spam_policy": true,
"email_use_type": "transactional",
"oversight_email": "ops@greenline.studio"
}
Response includes a default_mailbox address (e.g. agent@greenline.multimail.dev) and a pending status. Check your oversight email for an activation code, then confirm via POST /v1/confirm to activate and receive your API key (shown once). Manage your account at /dashboard.
Note: operator_name is published in the signed X-MultiMail-Identity header on every outbound email and visible to email recipients.
| Plan | Price | Mailboxes | Emails/mo | Storage |
|---|---|---|---|---|
| Starter | Free | 2 | 200 | 100 MB |
| Builder | $9/mo | 5 | 5,000 | 10 GB |
| Pro | $29/mo | 25 | 30,000 | 50 GB |
| Scale | $99/mo | 100 | 150,000 | 150 GB |
See full pricing with annual discounts and subscribe →
// Stripe (card) — supports monthly or annual billing
POST /v1/billing/checkout
{ "plan": "builder", "interval": "annual" } // builder | pro | scale
// Crypto (Coinbase Commerce -- one-time annual payment)
POST /v1/billing/crypto-checkout
{ "plan": "builder" }
Both return { "url": "https://..." }. Stripe handles recurring subscriptions; Coinbase Commerce processes a one-time payment for the annual term. Complete payment at that URL or pass it to your operator.
POST /v1/mailboxes/{mailbox_id}/send
{
"to": ["recipient@example.com"],
"subject": "Weekly summary",
"markdown": "## Completed\n\n- Task A\n- Task B\n\nAll items resolved."
}
Returns 200 if sent, 202 if held for operator approval (gated mode), or 403 if the mailbox is in read_only mode.
GET /v1/mailboxes/{mailbox_id}/emails?status=unread
Returns emails as markdown. Each email includes thread_id, from, to, subject, and attachment metadata.
POST /v1/mailboxes/{mailbox_id}/reply/{email_id}
{
"markdown": "Acknowledged. I'll follow up tomorrow."
}
Each mailbox has an oversight mode set via the API or by an admin. Modes form a trust ladder: start restrictive, upgrade as you earn trust.
read_only: you can receive and read email, but cannot send or reply. Attempts return 403 with instructions on how to request an upgrade.gated_all: both inbound and outbound require human approvalgated_send (default): outbound emails are held for approval. You receive a 202 instead of 200. Inbound delivered immediately.monitored: you operate freely, copies of outbound emails go to the oversight addressautonomous: full send/receive without approval gatesIf you receive a 202, the email is queued. Do not retry. The oversight address will be notified.
If your mailbox is in a restrictive mode and you need more autonomy, request an upgrade:
POST /v1/mailboxes/{mailbox_id}/request-upgrade
{ "target_mode": "gated_all" }
This emails a one-time upgrade code to your operator. Ask your operator to share it with you, then:
POST /v1/mailboxes/{mailbox_id}/upgrade
{ "code": "A7X-29K" }
Codes expire after 24 hours and can only be used once. No code is needed for downgrades. Use PATCH /v1/mailboxes/:id to move to a more restrictive mode at any time.
attachments array with name, content_base64, content_type. Max 10MB total.attachments with metadata. Download via GET /v1/mailboxes/:id/emails/:eid/attachments/:filename.Configure webhooks on your mailbox to receive push notifications instead of polling. Two webhook types are available:
webhook_url — notifies the agent when new email arrives (email.received)oversight_webhook_url — notifies the operator when an email is held for approval (email.pending_approval)Set either via POST /v1/mailboxes or PATCH /v1/mailboxes/:id. Both must use HTTPS.
All webhooks deliver a POST request with a JSON body:
{
"event": "email.received",
"timestamp": "2026-02-26T12:00:00.000Z",
"data": {
"email_id": "em_abc123",
"from": "sender@example.com",
"to": ["agent@yourco.multimail.dev"],
"subject": "Weekly report",
"direction": "inbound",
"has_attachments": false
}
}
For email.pending_approval, the data object also includes an approval_url for one-click approve/reject.
Every webhook request includes an X-MultiMail-Signature header containing an HMAC-SHA256 signature of the raw request body. Verify it server-side to confirm the request came from MultiMail.
Failed deliveries (non-2xx response) are retried up to 3 times with exponential backoff. View delivery history and debug failures via GET /v1/webhook-deliveries (requires admin scope).
If you don't use webhooks, poll GET /v1/mailboxes/:id/emails?status=unread instead.
If your framework supports the Model Context Protocol (MCP), use our MCP server instead of direct API calls. One config line gives you thirty-five email tools.
No install required. Connect directly to our hosted MCP server at mcp.multimail.dev. Authenticates via OAuth in the browser — paste your API key once and you're connected. Works with Claude.ai, Claude Desktop, Claude Code, and any client that supports remote MCP.
{
"mcpServers": {
"multimail": {
"type": "url",
"url": "https://mcp.multimail.dev/mcp"
}
}
}
Run the server locally via npm. API key is passed as an environment variable. Works with all MCP-compatible clients. Package: @multimail/mcp-server
{
"mcpServers": {
"multimail": {
"command": "npx",
"args": ["-y", "@multimail/mcp-server"],
"env": {
"MULTIMAIL_API_KEY": "mm_live_...",
"MULTIMAIL_MAILBOX_ID": "01KJ1NHN8J..."
}
}
}
}
MULTIMAIL_API_KEY (required): your API key. Server refuses to start without it.MULTIMAIL_MAILBOX_ID (optional): default mailbox ID so you don't need to pass it on every tool call. If not set, call list_mailboxes first.MULTIMAIL_API_URL (optional): override API base URL for local development. Defaults to https://api.multimail.dev.list_mailboxes: List all mailboxes available to this API key. Returns each mailbox's ID, email address, oversight mode, and display name. No arguments.
send_email: Send an email with a markdown body. Args: to (string[]), subject (string), markdown (string), cc (string[], optional), bcc (string[], optional), attachments (array of {name, content_base64, content_type}, optional), idempotency_key (string, optional), mailbox_id (string, optional). Returns { id, status, thread_id } where status is "pending_scan". For gated mailboxes, transitions to "pending_send_approval". Do not retry or resend. Use idempotency_key to prevent duplicate sends (24h TTL).
check_inbox: List email summaries with filtering. Args: status (unread/read/archived/deleted/pending_send_approval/pending_inbound_approval/rejected/cancelled/send_failed, optional), sender (string, partial match, optional), subject_contains (string, optional), date_after / date_before (ISO datetime, optional), direction (inbound/outbound, optional), has_attachments (boolean, optional), since_id (string, for incremental polling, optional), limit (number, max 100, optional), cursor (string, pagination cursor, optional), mailbox_id (string, optional). Returns array of { id, from, to, subject, status, received_at, has_attachments, delivered_at, bounced_at, bounce_type }. Does NOT include the email body. Call read_email for full content.
read_email: Get full email content including markdown body, attachment metadata, delivery timestamps, and tags. Args: email_id (string), mailbox_id (string, optional). Automatically marks unread emails as read. Returns delivered_at, bounced_at, bounce_type, approved_at, approved_by, and tags.
reply_email: Reply to an email in its existing thread. Threading headers set automatically. Args: email_id (string), markdown (string), cc (string[], optional), bcc (string[], optional), attachments (array, optional), idempotency_key (string, optional), mailbox_id (string, optional). Returns { id, status, thread_id }. Same scanning and approval behavior as send_email.
download_attachment: Download an email attachment as base64-encoded data. Args: email_id (string), filename (string, from read_email attachment list), mailbox_id (string, optional). Returns { filename, content_type, content_base64, size_bytes }.
get_thread: Get all emails in a conversation thread, ordered chronologically. Args: thread_id (string, from check_inbox or read_email), mailbox_id (string, optional). Returns participants, message_count, last_activity, has_unanswered_inbound, and the full email list.
cancel_message: Cancel a pending email. Args: email_id (string), mailbox_id (string, optional). Works on emails with status pending_scan, pending_send_approval, or pending_inbound_approval. Returns 409 if already sent. Idempotent on already-cancelled emails.
tag_email: Set, get, or delete key-value tags on emails. Tags persist across sessions. Args: email_id (string), action (set/get/delete), tags (Record<string, string>, for set), key (string, for delete), mailbox_id (string, optional). Use for priority flags, follow-up dates, extracted data, or any agent metadata.
add_contact: Add a contact to your address book. Args: name (string), email (string), tags (string[], optional). Build contacts organically from processed messages.
search_contacts: Search address book by name or email (partial match). Args: query (string, optional). Returns matching contacts with tags. Call with no query to list all.
update_mailbox: Update mailbox settings. All fields optional — only include what you want to change. Args: mailbox_id (string, optional), display_name (string, optional), oversight_mode (string, optional), auto_cc (string, optional), auto_bcc (string, optional), forward_inbound (boolean, optional), webhook_url (string, optional), oversight_webhook_url (string, optional), signature_block (string, optional).
update_account: Update account settings. Args: name (string, optional), oversight_email (string, optional), physical_address (string, optional). Requires admin scope.
delete_mailbox: Permanently delete a mailbox and all associated data. Args: mailbox_id (string). Requires admin scope. This action cannot be undone.
resend_confirmation: Resend the operator activation email with a new code. No arguments. Rate limited to 1 request per 5 minutes. Only works for unconfirmed accounts.
activate_account: Activate your account using the code from the confirmation email. Args: code (string, e.g. "SKP-7D2-4V8"). Accepts with or without dashes. Rate limited to 5 attempts per hour.
get_account: Get account status, plan, quota used/remaining, sending enabled, and enforcement tier. No arguments. Use for self-diagnosis when sends fail.
create_mailbox: Create a new mailbox. Args: address_local_part (string), display_name (string, optional), oversight_mode (string, optional). Requires admin scope.
request_upgrade: Request an oversight mode upgrade. Args: mailbox_id (string, optional), target_mode (string). Sends upgrade request to operator. Requires admin scope.
apply_upgrade: Apply an upgrade code from operator. Args: mailbox_id (string, optional), code (string).
get_usage: Check quota and usage stats. Args: period (summary/daily, optional). Returns emails sent, received, storage used, plan limits.
list_pending: List emails awaiting oversight decision. No arguments. Requires oversight or oversight_read scope.
decide_email: Approve or reject a pending email. Args: email_id (string), action (approve/reject), reason (string, optional). Requires oversight scope.
delete_contact: Delete a contact. Args: contact_id (string).
check_suppression: List suppressed email addresses. Args: limit (number, optional), cursor (string, optional).
remove_suppression: Remove address from suppression list. Args: email_address (string).
list_api_keys: List all API keys with metadata. No arguments. Requires admin scope.
create_api_key: Create a new API key. Args: name (string), scopes (string[]). Requires admin scope. Key value returned only once.
revoke_api_key: Revoke an API key. Args: key_id (string). Requires admin scope. Cannot be undone.
get_audit_log: Get account audit log. Args: limit (number, optional), cursor (string, optional). Requires admin scope.
delete_account: Permanently delete account and all data. No arguments. Requires admin scope. Cannot be undone.
wait_for_email: Block until a new email arrives matching optional filters, or timeout. Args: mailbox_id (string, optional), timeout_seconds (number, 5–120, default 30), filter ({sender?, subject_contains?}, optional). Returns immediately when mail arrives.
create_webhook: Create a webhook subscription for real-time email event notifications. Args: url (HTTPS string), events (string[]), mailbox_id (string, optional). Returns subscription with signing_secret.
list_webhooks: List all webhook subscriptions for this account. No arguments.
delete_webhook: Delete a webhook subscription. Args: webhook_id (string).
401: Invalid API key. Check MULTIMAIL_API_KEY.403: API key lacks required scope for this operation.429: Rate limit exceeded. Retry after the indicated seconds.400: Validation error, content filter, or suppression list. Error message passed through from API.Fetch GET /v1/openapi.json for full request/response schemas.
POST /v1/account create tenant, get API key and mailboxGET /v1/account your account info and quotaPATCH /v1/account update tenant settings (name, oversight email, address)DELETE /v1/account permanently delete account and all data (admin scope)POST /v1/account/resend-confirmation resend operator confirmation email (rate limited)POST /v1/billing/checkout get Stripe payment URLPOST /v1/billing/crypto-checkout get Coinbase Commerce payment URLPOST /v1/mailboxes create additional mailboxGET /v1/mailboxes list your mailboxesPOST /v1/mailboxes/:id/send send email as markdownGET /v1/mailboxes/:id/emails list inbox (filterable by status)GET /v1/mailboxes/:id/emails/:eid get single email with markdown bodyGET /v1/mailboxes/:id/emails/:eid/attachments/:filename download attachmentPOST /v1/mailboxes/:id/reply/:eid reply in-threadPOST /v1/mailboxes/:id/request-upgrade request oversight mode upgrade (emails code to operator)POST /v1/mailboxes/:id/upgrade redeem upgrade code to change oversight modeGET /v1/usage usage stats for current periodGET /.well-known/multimail-signing-key public key for verifying X-MultiMail-Identity signaturesInclude your API key in every request:
Authorization: Bearer mm_live_...
API keys have scopes: read, send, admin, oversight, oversight_read. The oversight_read scope allows viewing pending emails without approve/reject permission. If a request returns 403, the key lacks the required scope.
Support: support@multimail.dev
Any API can deliver a message. None of them tell the recipient who built the agent, who's responsible for what it sends, or whether a human reviewed the output before it went out.
Every outbound email carries a signed X-MultiMail-Identity header: the operator,
oversight mode, and verification status, signed with ECDSA P-256.
Every outbound email from a MultiMail address carries a cryptographically signed X-MultiMail-Identity header. The header contains a base64url-encoded JSON payload (operator name, oversight mode, capabilities, and verification status) plus an ECDSA P-256 signature. Recipients verify the signature against the public key at /.well-known/multimail-signing-key.
A separate X-MultiMail-Reputation header (an HMAC hash) links to reputation data with bounce rates, complaint rates, and account age. Updated daily, privacy-preserving, no raw addresses exposed.
Sign up, get an email address with signed identity on every email, and start sending. Use the web dashboard or go fully programmatic via API.
Follow the setup link from your beta invite, or
POST to /v1/account with your operator details.
Confirm via email to get your API key and a default mailbox like
agent@you.multimail.dev.
Outbound markdown becomes properly formatted HTML email. Inbound HTML is converted to clean markdown. Never touch raw MIME.
Every mailbox has configurable human oversight. Mirror copies, send-gating, or full approval flows. The oversight mode is published in the signed identity header on every outbound email.
Every mailbox has a configurable oversight mode. Start read-only, graduate through gated modes as you build trust, or let experienced agents run autonomously. Agents can request upgrades; you approve via a one-time code.
Markdown-native, thread-aware, and designed for machine-speed operation.
Send markdown and it arrives as formatted HTML. Receive email and HTML is converted to clean markdown. A typical email goes from ~12,000 tokens to under 1,000. No MIME decoding, no HTML parsing.
Automatic thread tracking via Message-ID and In-Reply-To headers. Follow and reply to email threads naturally.
Send and receive attachments. Files stored with zero egress fees. Download on demand, never inlined as base64.
Get notified via webhook when new email arrives, or poll the inbox. Webhook deliveries tracked with automatic retries on failure.
Distributed edge infrastructure. Fast API responses no matter where your agent runs.
Granular permissions: read, send, admin, oversight, oversight_read. Give your agent send access. Keep oversight and admin scopes for humans. Agents can't approve their own emails.
Identity is meaningless if the email lands in spam. We take deliverability and sender reputation seriously.
Every outbound email is signed with DKIM. SPF records and DMARC policies are published for every tenant subdomain. Bounce handling and suppression lists maintained automatically. Emails land in inboxes, not spam.
Each tenant subdomain builds its own sending reputation independently. MultiMail's platform-wide abuse prevention keeps the parent domain clean, giving new subdomains a head start. Your agent's behavior matters: bounce rates, complaint rates, and rejection rates are tracked per-mailbox daily. Abuse triggers automatic sending suspension.
Unsubscribe headers, physical address footers, and one-click opt-out built into every outbound email. Legally compliant by default.
Every email sent, received, approved, and rejected is logged. Full audit history available via API for compliance and debugging.
No single server to go down. Inbound email is queued even during maintenance. Never miss a message because of infrastructure.
Each account is fully isolated. Per-tenant subdomains with independent DKIM signing. One account's bounce rate can't affect another's deliverability.
Skip the API integration. Connect to our hosted server or run locally — either way, one config line gets you email tools instantly.
Add the server to your MCP config. The tools handle authentication,
error handling, and the pending-approval flow automatically. Just
call send_email and check_inbox.
| Variable | Description | |
|---|---|---|
| MULTIMAIL_API_KEY | Your API key (mm_live_...) | required |
| MULTIMAIL_MAILBOX_ID | Default mailbox ID. Skip passing it on every call. | optional |
| MULTIMAIL_API_URL | Override base URL for local development | optional |
Full OpenAPI spec at /v1/openapi.json
Every address publishes its operator, oversight mode, and reputation. Join the beta waitlist.