Documentation

Your agent has an inbox
in four steps.

Connect any email account, paste one URL into an OAuth-capable MCP client and authorize. Clients without OAuth use an API key instead. Full tool reference and connection guide below.

Quick startOAuth (claude.ai)Tool referenceSafety modelProvider support
Quick start

Up and running in minutes.

No SDK required. MCPEmails speaks standard MCP over HTTP, so it drops into any MCP-compatible agent.

01Sign up & connect an inbox

Create your account and connect Gmail

Sign up at mcpemails.com, then go to Dashboard → Inboxes → Connect Inbox. Pick Gmail, iCloud, Fastmail, or any IMAP inbox, then complete the OAuth flow or paste an app password. Your inbox is ready in under a minute.

Connect your inbox →
02Create an API key

Generate a bearer token for your agent

In Dashboard → API Keys, click "Create key". Name it, select the scopes your agent needs — read:email, search:email, send:email, manage:folders, delete:email, manage:drafts, manage:contacts, schedule:email, and manage:automations — and copy the key. It is shown only once.

# Your key looks like this:
mcpe_live_AbCdEfGhIjKlMnOpQrStUvWxYz123456
03Add MCPEmails to your agent

Paste the MCP endpoint into your client

Pick the tab for your client below. MCP clients with OAuth 2.0 support (claude.ai, Claude Desktop, Cursor, and others) just paste the URL and authorize, no API key needed. Clients without OAuth, plus scripted access, use the API key from step 02.

json
# OAuth-capable clients (claude.ai, Claude Desktop, Cursor…)
# No API key required. Paste the URL, click Connect, authorize.
#
# Example: claude.ai
#   1. Go to claude.ai → Customize → Connectors
#   2. Click "Add connector" and paste this URL:
#
#        https://mcpemails.com/api/mcp
#
#   3. Click Connect and sign in with your mcpemails account.
#   4. Every tool your approved scopes allow is live immediately.
#
# Claude Desktop and Cursor follow the same OAuth flow when
# the server URL is configured in their MCP settings.
04Make your first call

Ask your agent to check your inbox

No copy-pasting inbox UUIDs. Your agent calls inbox_list first to discover every connected inbox and its UUID, then you ask: "Check my inbox and summarise the last 5 unread messages."

# The agent calls inbox_list first, so no hardcoded UUIDs.
# System prompt (optional, for multi-inbox setups):
You have access to email via MCPEmails.
Start by calling inbox_list to discover available inboxes.
Endpoint

One URL, standard MCP.

All traffic goes to a single Streamable HTTP endpoint. Authenticate with a bearer token from your dashboard.

POSThttps://mcpemails.com/api/mcp

Send a JSON-RPC 2.0 request body. Supported methods: initialize, tools/list, tools/call, prompts/list, and prompts/get.

Transport: Streamable HTTP (MCP 2025-06-18)
Auth: Authorization: Bearer <api-key>
Rate limits: 100 req/min · 1,000/hr · 10,000/day per key, plus your plan's workspace ceiling
Response format: JSON-RPC 2.0 — successful results also carry a typed structuredContent object
Initialize handshake
bash
curl -X POST https://mcpemails.com/api/mcp \
  -H "Authorization: Bearer mcpe_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "clientInfo": { "name": "my-agent", "version": "1.0" },
      "capabilities": {}
    }
  }'
Polling, not push

MCPEmails is request/response only: every result comes from a tool call your agent makes. There are no webhooks, push notifications, or server-initiated events — an incoming email never triggers an agent call on its own. To react to new mail, have your agent poll on a schedule, e.g. call email_read with action: "list" and unread_only: true at whatever interval your workflow needs (mind the rate limits above).

Built for real inbox work

More control, without more tool clutter.

These are provider-aware capabilities of the same compact, action-based MCP interface — not a separate tool catalogue for every edge case.

Server-enforced send approval

Enable approval per inbox in the dashboard to hold sends, replies, forwards, draft sends, and scheduled sends. The agent receives a pending result; a workspace member approves or rejects it in the dashboard before anything is sent.

Provider compatibility profiles

Call inbox_list to see a versioned profile for each inbox. It identifies normalized operations as exact, different, or unavailable, so agents can choose portable workflows without pretending providers are identical.

Attachments and original email

Read a selected attachment as transient text for supported text files, CSV, HTML, JSON, and text-layer PDFs, or download the provider-stored original as a portable .eml. Extraction does not run embedded code or OCR images.

Reliable, reviewable automation

Reuse an idempotency_key to retry the same outbound request safely for 24 hours. Bulk organization runs keep dashboard status and accept cancellation requests; no message content or search terms are stored in those run records.

Guided MCP workflows

Clients that support MCP prompts can offer built-in routines for careful inbox triage, open-loop review, reply-draft preparation, organization proposals, and scheduled-send review. Prompts never grant permissions or run automatically.

Threaded reply drafts and Gmail Send As

Create an unsent reply in its original conversation for human review. Gmail sends, replies, and forwards can select only a provider-verified Send As identity returned by inbox_list; other providers use their connected address.

OAuth connection

Zero-config for OAuth-capable clients.

MCP clients that support OAuth 2.0 (claude.ai, Claude Desktop, Cursor, and others) connect automatically via authorization code + PKCE. No API key, no config file. Paste the URL and click Connect.

Step 1: Go to claude.ai → Customize → Connectors → Add connector
Step 2: Paste https://mcpemails.com/api/mcp as the server URL
Step 3: Click Connect. MCPEmails opens an authorization screen
Step 4: Sign in with your mcpemails account and approve access
Done: Every tool your approved scopes allow is live. claude.ai refreshes tokens automatically

How it works under the hood

claude.ai registers itself via RFC 7591 Dynamic Client Registration, so you never pre-register a client ID.

Authorization uses OAuth 2.0 Authorization Code + PKCE (RFC 7636), so no client secret is ever transmitted.

Tokens are scoped to exactly the permissions you approve — read:email, search:email, send:email, manage:folders, delete:email, manage:drafts, manage:contacts, schedule:email, and manage:automations.

Using a client without OAuth support? Create an API key in Dashboard → API Keys and pass it as a bearer token. API key and OAuth connections use the same MCP endpoint and the same tool catalogue.
Tool reference

11 tools. Every email operation your agent needs.

Targeting an inbox is optional. When your key has exactly one inbox, every per-inbox tool auto-resolves it — no inbox_id needed. With multiple inboxes, pass either inbox_id (the UUID from inbox_list) or inbox (the inbox's email address). Most tools take an action argument that selects the operation; the badges show the scope(s) each one needs, and tools/list only returns the tools your key (or OAuth token) is scoped for. Click "Show example" to see a full request and response.

inbox_listread:email

Returns every inbox the current API key or OAuth token can access. Call this first to discover inbox_id values, so you never copy-paste UUIDs from the dashboard. Each result includes the email address, provider, optional service brand (icloud/yahoo/zoho/yandex/generic/fastmail), a capabilities object, and a versioned compatibility profile. The profile labels each normalized operation exact, different, or unavailable so an agent can choose a portable workflow without hiding provider differences.

ParameterTypeRequiredDescription
providerenumoptionalOptional filter — return only inboxes served by this provider. One of: gmail, fastmail, imap. Omit to list every inbox the key can access.
include_capabilitiesbooleanoptionalWhether each inbox includes its capabilities object and compatibility profile. Default true; set false for a compact list of just inbox_id, email address, display name, provider, and service brand.
email_readread:emailsearch:email

Read, list, and search messages in an inbox. Set action: 'list' for recent message summaries (newest first, with folder/unread filtering and pagination), 'read' for the full content of one message_id (text body, optional sanitized HTML and attachments), 'read_batch' to fetch up to 50 message_ids in one call, 'search' for structured, provider-agnostic filters (from, to, cc, subject, body, text, unread, has_attachment, flagged, since, before), 'attachment' to download a single attachment (by attachment_index or filename), returned in the MCP-native content block for its type (image/audio/embedded resource) — up to 25 MB, 'extract' to return readable text from one selected attachment without returning its bytes, or 'original' to download the complete provider-stored MIME message as a portable .eml file — up to 25 MB. Original messages are returned as a saveable resource, never rendered or sanitized as model text. Extraction is transient and supports text, JSON, CSV/TSV, HTML, and best-effort text-layer PDF extraction; it does not perform OCR or execute embedded code. Read-only — never changes anything. The 'search' action is also unlocked on its own by the narrower search:email scope. Long bodies come back in windows: check body_truncated, then pass body_next_offset back as body_offset to continue.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "list" (recent message summaries), "read" (full content of one message_id), "read_batch" (several message_ids), "search" (structured filters), "attachment" (download one attachment as base64), "extract" (read one attachment as text, without returning its bytes), or "original" (download one complete provider-stored MIME message as a .eml file). Determines which other arguments apply.
inbox_idstring (uuid)optionalUUID of the inbox to read from. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to discover inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
message_idstringoptionalProvider message ID to read (actions 'read', 'attachment', or 'original'), from a prior list or search.
message_idsarray[string]optionalProvider message IDs to read (action 'read_batch'), from a prior list or search. Max 50 per call.
folderstringoptionalFolder to list (action 'list'). Default "INBOX". Other values: "SENT", "DRAFTS", "TRASH".
unread_onlybooleanoptionalReturn only unread messages (action 'list'). Default false.
limitintegeroptionalMax results to return (action 'list' or 'search'). Default 20, max 100.
offsetintegeroptionalZero-based pagination offset (action 'list' or 'search'). Default 0.
include_htmlbooleanoptionalInclude sanitized HTML body (action 'read'/'read_batch'). Default false.
include_attachmentsbooleanoptionalInclude base64 attachment data (action 'read'/'read_batch'). On 'read_batch' the 10 MB total is shared across all messages in the call. Default false.
mark_as_readbooleanoptionalMark the message(s) as read after fetching (action 'read'/'read_batch'). Default false.
fromstringoptionalSender to match (action 'search'): email address, display name, or fragment (e.g. "alice@example.com" or "Alice").
tostringoptionalPrimary (To) recipient to match (action 'search'): email address, display name, or fragment.
ccstringoptionalCarbon-copy (Cc) recipient to match (action 'search'): email address, display name, or fragment.
subjectstringoptionalText to match in the subject line (action 'search'). Multi-word phrases are matched as-is.
bodystringoptionalFree text to find in the message body (action 'search'). (On Gmail this matches the whole message, not body-only.)
textstringoptionalFree text to match anywhere in the message — headers and body (action 'search').
unreadbooleanoptionalAction 'search': true = only unread messages; false = only read messages; omit for either.
has_attachmentbooleanoptionalAction 'search': true = only messages with an attachment. Not supported on generic IMAP (ignored there).
flaggedbooleanoptionalAction 'search': true = only flagged/starred messages. Not supported on Outlook/Graph (ignored there).
sincestring (ISO date)optionalISO 8601 date or datetime (action 'search'); return messages received on/after (>=) this instant. E.g. "2026-06-01".
beforestring (ISO date)optionalISO 8601 date or datetime (action 'search'); return messages received strictly before (<) this instant.
querystringoptionalRaw provider-native query string (action 'search', escape hatch). Prefer the structured fields above. Combined with them where supported; ignored on Fastmail.
include_foldersarrayoptionalRestrict a search to these folder names (action 'search'). Default: search all folders.
email_organizemanage:folders

Move, copy, flag, or archive messages. Set action: 'move'/'move_batch' (relocate to a destination_folder_id), 'copy'/'copy_batch' (duplicate into a destination_folder_id, leaving the original in place; IMAP, Outlook and Fastmail only), 'flag' (set read/unread/flagged via flag_action on message_ids), 'archive' (move out of the Inbox, non-destructive), or 'search_and_move' (apply to every message matching a structured search, which avoids stale message IDs). On Gmail, move adds the destination label and removes INBOX; other labels remain, and native copy is unavailable. Each action needs the scope that matches it: manage:folders for moves and copies, send:email for flag/archive. Deleting messages lives in its own email_delete tool.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "move", "move_batch", "copy", "copy_batch", "flag", "archive", or "search_and_move". Determines which other arguments apply and which scope is required.
inbox_idstring (uuid)optionalUUID of the inbox that owns the messages. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
message_idstringoptionalProvider message ID for a single-message action (move, copy, archive), from a prior list, read, or search.
message_idsarray[string]optionalProvider message IDs for a batch action (move_batch, copy_batch, flag). Max 500 per call.
destination_folder_idstringoptionalDestination folder (move, move_batch, copy, copy_batch, search_and_move): a canonical alias (inbox, sent, drafts, trash, archive, spam), a folder/label name (e.g. 'Receipts'), or a provider-native folder ID from the folder list action. Names and aliases are resolved automatically.
flag_actionenumoptionalFor action 'flag': the change to apply to every message — "read" or "unread" to set read status, or "flag"/"unflag" to add or remove a star/follow-up flag.
fromstringoptionalSender to match (search_and_move): email address, display name, or fragment.
tostringoptionalPrimary (To) recipient to match (search_and_move): email address, display name, or fragment.
ccstringoptionalCarbon-copy (Cc) recipient to match (search_and_move): email address, display name, or fragment.
subjectstringoptionalText to match in the subject line (search_and_move).
bodystringoptionalFree text to find in the message body (search_and_move). (On Gmail this matches the whole message.)
textstringoptionalFree text to match anywhere in the message — headers and body (search_and_move).
unreadbooleanoptionalSearch actions: true = only unread; false = only read; omit for either.
has_attachmentbooleanoptionalSearch actions: true = only messages with an attachment. Not supported on generic IMAP (ignored there).
flaggedbooleanoptionalSearch actions: true = only flagged/starred messages. Not supported on Outlook/Graph (ignored there).
sincestring (ISO date)optionalISO 8601 date or datetime (search actions); match messages received on/after (>=) this instant.
beforestring (ISO date)optionalISO 8601 date or datetime (search actions); match messages received strictly before (<) this instant.
querystringoptionalRaw provider-native query string (search actions, escape hatch). Prefer the structured fields above. Ignored on Fastmail.
include_foldersarrayoptionalRestrict the search to these folder names (search actions). Default: all folders.
limitintegeroptionalFor search_and_move: maximum number of matches to act on. Default 500, max 500.
email_deletedelete:email

Delete messages — its own tool, separate from email_organize, because deleting is destructive. Set action: 'delete'/'delete_batch' (Trash by default, or permanent), or 'search_and_delete' (delete every message matching a structured search — avoids stale message IDs). Deletes go to Trash unless you pass permanent: true, which is irreversible. Every action needs the delete:email scope, and the whole tool is flagged as destructive to your MCP client, which handles user confirmation before anything is removed.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "delete", "delete_batch", or "search_and_delete". Determines which other arguments apply.
inbox_idstring (uuid)optionalUUID of the inbox that owns the messages. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
message_idstringoptionalProvider message ID for a single delete (action 'delete'), from a prior list, read, or search.
message_idsarray[string]optionalProvider message IDs for a batch delete (action 'delete_batch'). Max 500 per call.
permanentbooleanoptionalWhen true, hard-delete (bypass Trash; may be irreversible); when false or omitted, move to Trash. Permanent expunge is available on IMAP and Fastmail; Gmail and Outlook support trash only. Default false.
fromstringoptionalSender to match (search_and_delete): email address, display name, or fragment.
tostringoptionalPrimary (To) recipient to match (search_and_delete): email address, display name, or fragment.
ccstringoptionalCarbon-copy (Cc) recipient to match (search_and_delete): email address, display name, or fragment.
subjectstringoptionalText to match in the subject line (search_and_delete).
bodystringoptionalFree text to find in the message body (search_and_delete). (On Gmail this matches the whole message.)
textstringoptionalFree text to match anywhere in the message — headers and body (search_and_delete).
unreadbooleanoptionalSearch action: true = only unread; false = only read; omit for either.
has_attachmentbooleanoptionalSearch action: true = only messages with an attachment. Not supported on generic IMAP (ignored there).
flaggedbooleanoptionalSearch action: true = only flagged/starred messages. Not supported on Outlook/Graph (ignored there).
sincestring (ISO date)optionalISO 8601 date or datetime (search action); match messages received on/after (>=) this instant.
beforestring (ISO date)optionalISO 8601 date or datetime (search action); match messages received strictly before (<) this instant.
querystringoptionalRaw provider-native query string (search action, escape hatch). Prefer the structured fields above. Ignored on Fastmail.
include_foldersarrayoptionalRestrict the search to these folder names (search action). Default: all folders.
limitintegeroptionalFor search_and_delete: maximum number of matches to act on. Default 500, max 500.
email_composesend:email

Send new mail or respond to existing messages. Set action: 'send' for a new email (to/subject/body, optional cc/bcc/html_body/reply_to/attachments), 'reply' to answer a message_id (threading headers are set automatically; optional reply_all), or 'forward' a message_id to new recipients (optionally re-attaching the original files). The inbox's signature is appended automatically — on replies and forwards it sits after your text and before the quoted block, governed by the signature's reply mode; pass include_signature: false to suppress it for a single terse message. To retry automated sends safely, provide one idempotency_key per logical email and reuse it only for the same request within 24 hours. All three are irreversible once sent.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "send", "reply", or "forward". Determines which other arguments apply.
inbox_idstring (uuid)optionalUUID of the inbox to send from. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
message_idstringoptionalProvider message ID of the original message (action 'reply' or 'forward'), from a prior list, read, or search.
toarray[string]optionalRecipient email addresses (required for 'send' and 'forward'). Max 50.
subjectstringoptionalEmail subject line (action 'send'). Max 998 characters. On reply/forward it is derived from the original.
bodystringoptionalPlain-text body. For 'reply' this is your reply; for 'forward' an optional note prepended above the forwarded message.
ccarray[string]optionalCC recipients (send, forward). Default [].
bccarray[string]optionalBCC recipients (send, forward). Default [].
html_bodystringoptionalHTML version of the body (multipart/alternative). Caller is responsible for safe HTML.
reply_tostringoptionalReply-To header address (action 'send').
reply_allbooleanoptionalReply to all original recipients — To + Cc (action 'reply'). Default false.
include_attachmentsbooleanoptionalRe-attach the original message's attachments (action 'forward'). Files over the 10 MB budget are omitted. Default false.
include_signaturebooleanoptionalWhether to append the inbox's configured signature to this message. Default true; set false to send this one message without the signature.
attachmentsarrayoptionalFile attachments. Each item: { filename, mime_type, data (base64) }. Max 20 items, 10 MB total.
idempotency_keystringoptionalOptional opaque key (1–200 characters) for one logical outbound request. Reuse it only to retry the exact same action and arguments within 24 hours; a reuse with different arguments is rejected.
folderread:emailmanage:folders

Manage mailbox folders or Gmail labels. The action name and parameters use 'folder' for cross-provider compatibility, but Gmail returns and manages labels (type: 'label'), not folders. Set action: 'list' (every folder or label with its provider-native ID, display name, type, and message counts — use the IDs as the folder argument when listing mail and as a move destination), 'create' (name), 'rename' (folder_id, new_name), or 'delete' (folder_id — irreversible; messages inside may be lost depending on the provider). 'list' needs read:email; create/rename/delete need manage:folders, and delete is flagged as destructive to your MCP client.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "list", "create", "rename", or "delete". Determines which other arguments apply and which scope is required.
inbox_idstring (uuid)optionalUUID of the inbox whose folders to manage. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
namestringoptionalName of the new folder or label (action 'create'). 1–255 characters.
folder_idstringoptionalProvider-native folder/label ID (action 'rename' or 'delete'), from the folder list action.
new_namestringoptionalNew display name (action 'rename'). 1–255 characters.
draftmanage:drafts

Manage draft messages in the inbox's Drafts folder. Set action: 'list' (saved drafts, each with its draft_id, subject, recipients, and created timestamp), 'create' (subject/body required, optional to/cc/bcc/html_body), 'reply' (message_id/body required, optional reply_all — creates an unsent reply in the source conversation), 'update' (draft_id plus the fields to overwrite), or 'send' (draft_id — removes the draft and sends it, irreversible). Reply drafts require both manage:drafts and read:email but never send mail. The inbox's signature is embedded when the draft is created or updated, so it is already present in the Drafts folder and is not re-appended on send; pass include_signature: false to create a draft without it. On IMAP-backed inboxes a draft_id changes on every update, so always use the latest one; Gmail and Outlook keep a stable draft_id.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "list", "create", "reply", "update", or "send". Determines which other arguments apply.
inbox_idstring (uuid)optionalUUID of the inbox that owns the drafts. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
draft_idstringoptionalProvider draft ID (action 'update' or 'send'), from the most recent create, update, or list action. On IMAP inboxes it changes after every update, so always use the latest one.
subjectstringoptionalDraft subject line (action 'create'/'update').
bodystringoptionalPlain-text body of the draft (action 'create'/'update').
toarray[string]optionalRecipient addresses (action 'create'/'update'). Default [].
ccarray[string]optionalCC recipients (action 'create'/'update'). Default [].
bccarray[string]optionalBCC recipients (action 'create'/'update'). Default [].
html_bodystringoptionalOptional HTML body (action 'create'/'update').
include_signaturebooleanoptionalWhether to embed the inbox's configured signature in the draft (action 'create'/'update'). Default true; set false to save a draft without the signature.
idempotency_keystringoptionalOptional opaque key (1–200 characters) for one draft send. Reuse it only to retry the exact same send within 24 hours; a reuse with different arguments is rejected.
limitintegeroptionalMaximum number of drafts to return (action 'list'). Default 20, max 50.
scheduleschedule:email

Schedule mail for future delivery via a server-side queue. Set action: 'create' (to/subject/body plus a send_at ISO 8601 timestamp — recipients and body are validated immediately, and invalid sends are not queued), 'list' (pending scheduled sends, earliest first, optionally filtered by inbox), or 'cancel' (scheduled_send_id — only sends still 'pending' can be cancelled). The dispatcher runs every minute, so delivery may be up to 60 seconds after send_at.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "create", "list", or "cancel". Determines which other arguments apply.
inbox_idstring (uuid)optionalUUID of the inbox to send from (action 'create') or to filter by (action 'list'). Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
toarray[string]optionalRecipient email addresses (action 'create'). Max 50.
subjectstringoptionalEmail subject line (action 'create'). Max 998 characters.
bodystringoptionalPlain-text email body (action 'create').
send_atstring (ISO 8601)optionalISO 8601 datetime with timezone at which to send (action 'create'). Must be in the future, e.g. "2026-06-02T09:00:00Z".
ccarray[string]optionalCC recipients (action 'create'). Default [].
bccarray[string]optionalBCC recipients (action 'create'). Default [].
html_bodystringoptionalOptional HTML version of the body (action 'create').
reply_tostringoptionalOptional Reply-To header address (action 'create').
attachmentsarrayoptionalFile attachments (action 'create'). Same schema as the send action. Max 20 items, 10 MB total.
scheduled_send_idstring (uuid)optionalUUID of the scheduled send to cancel (action 'cancel').
idempotency_keystringoptionalOptional opaque key for one scheduled-send creation. Reuse it only to retry the exact same create request within 24 hours.
limitintegeroptionalMaximum number of results (action 'list'). Default 20, max 100.
automationmanage:automations

Create and manage unattended scheduled triage rules. A rule is a stored search plus one fixed action, re-evaluated on a fixed cadence with no model in the loop: mail is matched, never interpreted. Set action: 'create' (name, filter, rule_action and interval_minutes; a rule is always created disabled), 'list', 'get', 'update', 'enable', 'disable', 'delete' (the run history is kept), 'runs' (recent run counters), or 'preview' (a dry run that reports what a filter matches right now and applies nothing). The rule actions available are move, label (a Gmail label, an Outlook category or an IMAP keyword), mark_read, forward and draft_reply. Deleting mail is not available to an automation. A forward is always held for human approval whatever the inbox's approval setting says, and draft_reply only ever writes a draft. Preview before you enable. Every action needs manage:automations.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "create", "list", "get", "update", "enable", "disable", "delete", "runs", or "preview". Determines which other arguments apply.
automation_idstring (uuid)optionalUUID of the rule to act on, as returned by 'create' or 'list'. Required for get, update, enable, disable, delete and runs. Optional for preview: pass it to dry-run a stored rule instead of an ad-hoc filter.
inbox_idstring (uuid)optionalUUID of the inbox the rule watches ('create'), or the inbox to preview against. Optional when the key has exactly one inbox; otherwise pass this or inbox.
inboxstringoptionalEmail address of the inbox, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
namestringoptionalHuman-readable name for the rule, 1 to 80 characters. Required on 'create'.
filterobjectoptionalThe stored search, using the same structured criteria the email_read 'search' action accepts: from, to, cc, subject, body, text, unread, has_attachment, flagged, since, before. At least one criterion is required, because an empty filter would match your whole mailbox. Provider-native raw query strings are not accepted here: a rule re-runs unattended for months, and a raw string is a dialect nothing validates.
rule_actionobjectoptionalThe single fixed action applied to every match, as a tagged object with a type of move (plus folder), label (plus label; written as a Gmail label, an Outlook category, or an IMAP keyword), mark_read, forward (plus to, and an optional note), or draft_reply (plus template). It is called rule_action because action already selects the operation. There is no delete-shaped action and one is refused, not ignored. A forward is always held for approval, and draft_reply only writes a draft. A template substitutes only {{sender_name}}, {{sender_email}}, {{subject}} and {{date}}, each HTML-escaped; everything else is literal text and message bodies are never interpolated.
interval_minutesenumoptionalMinutes between runs, from the fixed ladder 15, 30, 60, 180, 360, 720 or 1440. Required on 'create'. A ladder rather than a free integer, so a one-minute rule cannot hammer a provider into rate limiting.
max_messages_per_runintegeroptionalHow many matching messages one run may act on: 1 to 200, default 25. This is the blast radius, capping how much mail a wrong filter can touch before a human reads the run log.
limitintegeroptionalFor action 'runs': how many runs to return, newest first. Default 20, max 100.
signatureread:emailsend:email

Read or configure the inbox's email signature, which is appended server-side on every send, reply, forward, draft, and scheduled message. Set action: 'get' (returns the current signature text and HTML, whether it is enabled, the reply/forward mode, and its source — 'manual', 'gmail_import', or null) or 'set' (write signature_text and/or signature_html, and optionally signature_enabled and signature_reply_mode). Signatures support rich HTML: bold, italic, headings, lists, colors, alignment, links, and hosted logo/images referenced as https URLs, so an agent can set a fully formatted signature by passing signature_html. The same rich editor is available in the dashboard. Setting a signature marks its source as 'manual', which permanently overrides Gmail auto-import for that inbox. 'get' needs read:email; 'set' needs send:email.

ParameterTypeRequiredDescription
actionenumrequiredWhich operation to perform: "get" (read the current signature) or "set" (write it). Determines which other arguments apply and which scope is required.
inbox_idstring (uuid)optionalUUID of the inbox whose signature to read or set. Optional — auto-resolved when the key has exactly one inbox; otherwise pass this or inbox. Call inbox_list to get available inbox IDs.
inboxstringoptionalEmail address of the inbox to use, as a friendly alternative to inbox_id. Optional; ignored if inbox_id is given.
signature_textstringoptionalPlain-text signature body (action 'set'). Omit to leave unchanged; pass an empty string to clear it. If only text is given, an HTML version is derived automatically on send.
signature_htmlstringoptionalOptional rich HTML signature body (action 'set'). Accepts formatting (bold, italic, underline, headings, lists, colors, alignment, links) and hosted images via <img> tags whose src is an https URL (no base64 or CID); it is sanitized on save. Omit to leave unchanged; pass an empty string to clear it.
signature_enabledbooleanoptionalWhether the signature is appended to outgoing mail (action 'set'). Default true; set false to stop appending without deleting the text.
signature_reply_modeenumoptionalWhen to include the signature on replies and forwards (action 'set'): "always" (every reply/forward), "first_only" (default — only the first message in a thread, avoiding double-signing), or "never".
Automation safety model

What a scheduled rule can and cannot do.

An automation touches your mailbox on a schedule with nobody watching. That is a different risk category from an agent you are talking to, so the guarantees below are enforced by the server rather than left to the rule you write.

No model runs unattended.

A rule is a stored query plus one fixed action. When it runs, the server executes the query against your mailbox and applies that action to the matches. Nothing reads your mail and then decides what to do with it. Email content is matched, never interpreted as an instruction, so prompt injection is structurally absent from the unattended path rather than filtered, scored, or otherwise mitigated. There is nothing in the loop for injected text to talk to.

This is worth saying plainly, because the dangerous shape in this category is an agent that reads untrusted inbound email and then acts on it with no human present. Public incidents, including EchoLeak and the backdoored Postmark MCP server, have left buyers reasonably wary of exactly that. In an interactive session a model does read your mail, which is the point of the product, and there a person is present and the content is marked as untrusted data. The scheduled path is the one that runs alone, and it contains no model at all.

Automations never delete mail.

Delete is not an available action, by design. Move, label, mark as read, forward, and draft a reply are the complete set. Deletion is the one action a misfiring rule makes irreversible, so it is excluded at the validation layer, where an action that merely names deletion is refused rather than quietly ignored.

Forwards always wait for a person.

A forward from an automation is queued to the approval queue and leaves your mailbox only after a workspace member approves it, regardless of the per-inbox send approval setting. Recipients are capped per rule. An unattended rule cannot move mail out of your organization on its own.

Draft replies only ever draft.

A draft_reply rule writes an unsent draft into the original conversation and stops there. Nothing is sent unattended, on any provider, under any configuration.

Templates substitute four fields, and nothing else.

A reply template is stored verbatim and never evaluated. Only {{sender_name}}, {{sender_email}}, {{subject}} and {{date}} are substituted, each HTML-escaped. Message body content is never interpolated, and there is no expression syntax to evaluate, so nothing arriving in your inbox can turn a template into a computation.

Every run is on the record.

Each run records what the filter matched, what happened to each message, and what was queued for approval, alongside counters for matched, processed, succeeded, failed, and skipped. Reversible actions keep the state needed to undo them. Run history outlives the rule it belongs to, because it is the record of what was done to your mailbox. Read it with action 'runs' or in the dashboard.

A rule has exactly one key's authority.

Each rule runs as the API key that created it. It can never exceed the scopes or the inbox access that key already has, every action it takes is metered, rate-limited, and written to the audit log exactly like an interactive call, and revoking the key stops the rule.

Repeated failure turns it off.

After 5 consecutive failed runs a rule is disabled automatically and the reason is recorded. A rule pointed at a mailbox that has stopped answering stops, instead of retrying against it every 15 minutes forever.

A capped blast radius per run.

Each rule carries a maximum number of messages a single run may act on, 1 to 200 and 25 by default, so a filter broader than you intended touches at most that many messages before you see the run log. A rule is also created disabled, and preview is a dry run that shows what a filter matches right now without applying anything.

Error codes

Error codes & retry guidance.

Auth, scope, and rate limit failures return a JSON-RPC error object with a numeric code. Tool execution failures (inbox not found, provider error, fair-use ceiling reached, etc.) return a normal result with isError: true and a human-readable message in content[0].text.

CodeTypeWhen it occursRetryable
-32001JSON-RPC errorMissing, malformed, revoked, or expired API key. Also returned when the API key lacks the required scope for the called tool.No
-32601JSON-RPC errorUnknown JSON-RPC method (e.g. calling a method other than initialize, tools/list, tools/call)No
-32602JSON-RPC errorUnknown tool name, or missing / invalid parameter in tools/callNo
-32003JSON-RPC errorPer-key or per-workspace rate limit exceeded (HTTP 429). data.error_code is always "rate_limit_exceeded". Wait data.retry_after seconds, or read the Retry-After header, before retrying.
isError: trueTool resultTool executed but encountered an error (inbox not found, message not found, provider auth failure, invalid recipient, attachment too large, provider 5xx). The error description is in content[0].text.No
isError: trueTool resultThe workspace has hit its fair-use ceiling on billable actions for the current billing period. Returned as a normal tool result with isError: true, not as a JSON-RPC error, with the details under _meta["com.mcpemails/usage_limit"]: error_code "usage_limit_reached" and reset_at. Retrying cannot succeed before reset_at.No
Example error responses
json
// Tool execution error: inbox not found
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "Inbox not found or not accessible." }],
    "isError": true
  }
}

// Rate limit: JSON-RPC error object with data (HTTP 429). Safe to retry
// after retry_after seconds.
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32003,
    "message": "Rate limit exceeded",
    "data": {
      "error_code": "rate_limit_exceeded",
      "window": "per_minute",
      "limit": 100,
      "used": 100,
      "retry_after": 34
    }
  }
}

// Fair-use ceiling: a normal tool result (HTTP 200) with isError: true.
// NOT a JSON-RPC error, and NOT retryable until reset_at.
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "content": [{
      "type": "text",
      "text": "Usage limit reached for this workspace. Calls resume at reset_at."
    }],
    "isError": true,
    "_meta": {
      "com.mcpemails/usage_limit": {
        "error_code": "usage_limit_reached",
        "reset_at": "2026-09-01T00:00:00.000Z",
        "dashboard_url": "https://mcpemails.com/dashboard/usage"
      }
    }
  }
}
Rate limits

Rate limits & fair use.

Per-key rolling windows

100 req / min · 1,000 / hr · 10,000 / day

Enforced per API key regardless of plan. When exceeded, the server returns HTTP 429 with JSON-RPC error code -32003, data.error_code: "rate_limit_exceeded" and a data.retry_after field (seconds). Respect that value before retrying: this is a short, retryable pause.

Plan per-minute ceiling

Free 60 / min · Pro 300 / min · Team 1,000 / min

A per-workspace fair-use burst limit, aggregated across all your API keys. When exceeded, calls return error code -32003 with data.error_code: "rate_limit_exceeded", data.window: "per_minute" and a data.retry_after countdown (seconds). Pro and Team raise the ceiling.

Fair-use ceiling

A stop, not a backoff

Every workspace has a fair-use ceiling on billable actions per billing period. It sits far above real usage and is not something you buy your way past, but a runaway agent can reach it. Hitting it is not a JSON-RPC error: the call returns HTTP 200 with a normal tool result carrying isError: true and a _meta["com.mcpemails/usage_limit"] block with error_code: "usage_limit_reached" and reset_at. There is no retry_after, because retrying cannot succeed before reset_at. Treat it as a stop, not a backoff.

Retrying safely

Always honour retry_after; never retry sends blindly

For rate_limit_exceeded errors, wait data.retry_after seconds before retrying. Use exponential backoff for provider_error. Do not auto-retry email_compose sends on provider_error, since the message may have already been accepted by the provider. Never retry usage_limit_reached: it clears only at reset_at.

Ready to connect your inbox?

Start on the Free plan: one connected inbox, forever, no card required. Pro connects every mailbox you own, and Team adds members, roles, and a workspace per client.