You're viewing the agent-readable version of this page. Switch to human view

MultiMail: Email for AI Agents

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_...

What this does for you

Verify before you communicate

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.

Getting started

1. Sign up

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.

2. Upgrade (optional)

PlanPriceMailboxesEmails/moStorage
StarterFree2200100 MB
Builder$9/mo55,00010 GB
Pro$29/mo2530,00050 GB
Scale$99/mo100150,000150 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.

3. Send an email

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.

4. Read your inbox

GET /v1/mailboxes/{mailbox_id}/emails?status=unread

Returns emails as markdown. Each email includes thread_id, from, to, subject, and attachment metadata.

5. Reply in-thread

POST /v1/mailboxes/{mailbox_id}/reply/{email_id}
{
  "markdown": "Acknowledged. I'll follow up tomorrow."
}

Oversight modes

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.

If you receive a 202, the email is queued. Do not retry. The oversight address will be notified.

Requesting an upgrade

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.

Handling attachments

Webhooks

Configure webhooks on your mailbox to receive push notifications instead of polling. Two webhook types are available:

Set either via POST /v1/mailboxes or PATCH /v1/mailboxes/:id. Both must use HTTPS.

Webhook payload

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.

Signature verification

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.

Retries and delivery history

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.

MCP Server

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.

Option A: Remote server (recommended)

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"
    }
  }
}

Option B: Local server (stdio)

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..."
      }
    }
  }
}

Environment variables (local server only)

Tools

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).

Error handling

All endpoints

Fetch GET /v1/openapi.json for full request/response schemas.

Authentication

Include 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

Your agent can send email.
No one receiving it can verify who's behind it.

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.

Cryptographically signed identity on every email

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.

X-MultiMail-Identity header
X-MultiMail-Identity: <payload>.<signature> Decoded payload: { "operator": "Greenline Studios", "oversight": "monitored", "capabilities": ["receive", "send", "reply"], "verified_operator": true, "created": "2026-02-22", "service": "multimail", "iat": 1740500000 }

Three steps from signup to sending

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.

1

Create your account

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.

2

Send & receive as markdown

Outbound markdown becomes properly formatted HTML email. Inbound HTML is converted to clean markdown. Never touch raw MIME.

3

Oversight is built in

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.


A trust ladder for agent autonomy

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.

read_only
Agent can receive and read email only. All sends blocked with upgrade instructions.
gated_all
Both inbound and outbound require human approval. Maximum control for sensitive use cases.
gated_send (default)
Outbound emails require human approval before delivery. Inbound delivered immediately.
monitored
Agent operates freely. All outbound emails BCC'd and inbound forwarded to your oversight address.
autonomous
Full send/receive without approval. For trusted, battle-tested agents.

Built for how agents work

Markdown-native, thread-aware, and designed for machine-speed operation.

Format

Markdown in, markdown out

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.

Conversation

Threaded conversations

Automatic thread tracking via Message-ID and In-Reply-To headers. Follow and reply to email threads naturally.

Files

Attachments

Send and receive attachments. Files stored with zero egress fees. Download on demand, never inlined as base64.

Events

Webhooks & polling

Get notified via webhook when new email arrives, or poll the inbox. Webhook deliveries tracked with automatic retries on failure.

Performance

Globally fast

Distributed edge infrastructure. Fast API responses no matter where your agent runs.

Access

Scoped API keys

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.


Trust the identity. Trust that the message arrives.

Identity is meaningless if the email lands in spam. We take deliverability and sender reputation seriously.

Emails that arrive

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.

Reputation you build

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.

CAN-SPAM compliant

Unsubscribe headers, physical address footers, and one-click opt-out built into every outbound email. Legally compliant by default.

Audit trail

Every email sent, received, approved, and rejected is logged. Full audit history available via API for compliance and debugging.

Always on

No single server to go down. Inbound email is queued even during maintenance. Never miss a message because of infrastructure.

Tenant isolation

Each account is fully isolated. Per-tenant subdomains with independent DKIM signing. One account's bounce rate can't affect another's deliverability.


One config line,
thirty-five email tools

Skip the API integration. Connect to our hosted server or run locally — either way, one config line gets you email tools instantly.

Zero-code setup

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
mcp config
{ "mcpServers": { "multimail": { "type": "url", "url": "https://mcp.multimail.dev/mcp" } } }
list_mailboxes
Discover available mailboxes, their addresses, and oversight modes.
no arguments
send_email
Send an email with a markdown body. Supports idempotency keys.
to · subject · markdown · cc? · bcc? · idempotency_key? · mailbox_id?
check_inbox
List emails with filters: sender, subject, date range, direction, attachments.
status? · sender? · subject_contains? · direction? · since_id? · mailbox_id?
read_email
Get full email content with markdown body and attachment metadata. Marks as read.
email_id · mailbox_id?
reply_email
Reply in-thread with markdown. Supports idempotency keys.
email_id · markdown · cc? · bcc? · idempotency_key? · mailbox_id?
download_attachment
Download email attachments as base64. Read inbound PDFs, images, docs.
email_id · filename · mailbox_id?
get_thread
Get full conversation thread with participants and unanswered status.
thread_id · mailbox_id?
cancel_message
Cancel a pending email awaiting oversight approval. Idempotent.
email_id · mailbox_id?
tag_email
Set, get, or delete key-value tags on emails. Persistent agent memory.
email_id · action · tags? · key? · mailbox_id?
add_contact
Add contacts to your address book with optional categorization tags.
name · email · tags?
search_contacts
Search address book by name or email. Partial match, case-insensitive.
query?
update_mailbox
Update mailbox settings: display name, oversight mode, signature, webhooks.
mailbox_id? · display_name? · oversight_mode? · signature_block? · …
update_account
Update account settings: org name, oversight email, physical address.
name? · oversight_email? · physical_address?
delete_mailbox
Permanently delete a mailbox and all associated data. Cannot be undone.
mailbox_id
resend_confirmation
Resend operator activation email. Rate limited to 1 per 5 minutes.
no arguments
activate_account
Activate account using the code from the confirmation email.
code
get_account
Check account status, plan, quota, and enforcement tier.
no arguments
create_mailbox
Create a new mailbox with optional oversight mode.
address_local_part · display_name? · oversight_mode?
request_upgrade
Request oversight mode upgrade. Trust ladder entry point.
target_mode · mailbox_id?
apply_upgrade
Apply an upgrade code from the operator approval email.
code · mailbox_id?
get_usage
Check quota and usage stats for the billing period.
period?
list_pending
List emails awaiting oversight decision. Requires oversight scope.
no arguments
decide_email
Approve or reject a pending email. Requires oversight scope.
email_id · action · reason?
delete_contact
Delete a contact from your address book.
contact_id
check_suppression
List suppressed email addresses that will bounce on send.
limit? · cursor?
remove_suppression
Remove an address from the suppression list.
email_address
list_api_keys
List all API keys with metadata. Requires admin scope.
no arguments
create_api_key
Create a new API key with specified scopes. Admin only.
name · scopes
revoke_api_key
Permanently revoke an API key. Admin only.
key_id
get_audit_log
Get chronological account audit log. Admin only.
limit? · cursor?
delete_account
Permanently delete account and all data. Cannot be undone.
no arguments
wait_for_email
Block until a new email arrives, or timeout. No polling needed.
mailbox_id? · timeout_seconds? · filter?
create_webhook
Subscribe to real-time email event notifications via HTTPS.
url · events · mailbox_id?
list_webhooks
List all webhook subscriptions for this account.
no arguments
delete_webhook
Delete a webhook subscription by ID.
webhook_id

REST endpoints

Full OpenAPI spec at /v1/openapi.json

POST
/v1/account
Create tenant + get API key
GET
/v1/account
Tenant info, quota, plan limits
PATCH
/v1/account
Update tenant settings
DELETE
/v1/account
Delete account and all data
POST
/v1/mailboxes/:id/send
Send markdown email
GET
/v1/mailboxes/:id/emails
List inbox, filter by status
GET
/v1/mailboxes/:id/emails/:eid
Full email with body + attachments
POST
/v1/mailboxes/:id/emails/:eid/reply
Reply in-thread
POST
/v1/oversight/decide
Approve or reject gated emails
POST
/v1/mailboxes/:id/request-upgrade
Request oversight mode upgrade
GET
/.well-known/multimail-signing-key
Public key for verifying identity signatures
GET
/v1/usage
Billing period usage stats

The only agent email with
a verifiable sender

Every address publishes its operator, oversight mode, and reputation. Join the beta waitlist.