Skip to main content
Glama
Apple Mail
by yu2001-s

Mail & Calendar

An MCP connector that runs as a Cloudflare Worker. It reads and searches iCloud mail directly over IMAP/SMTP, creates synchronized drafts, resolves threaded replies, and applies saved sender signatures. It does not launch Mail.app or use AppleScript.

The same connector serves any number of Gmail and Google Calendar accounts. One set of mail_* tools works the same for iCloud and every Gmail account, calendar tools work across every account, and one page links them.

Added once to a Claude or ChatGPT account, it works in every app and device signed in to that account, with nothing installed per machine. Clients that can run shell commands, such as Claude Code, can also attach local files through one-time upload links. Agents can also register webhooks that hear about new iCloud mail (mail_listen_set).

Guide

docs/WORKER.md

Deploy, connect clients, attachments, new-mail webhooks, security

docs/GOOGLE.md

Link Gmail and Google Calendar accounts

Mail tools

Every ID names its account (imap:… and apple-draft:… for iCloud, gmail:<kind>:<address>:<id> for Gmail), so a message found anywhere is read, answered and moved without naming the account again, and a draft's from address picks the account it is sent from.

Tool

mail_search

every account at once, or some; inbox by default, any folder or label, newest first, one cursor for more; with finds your mail with one person both ways

mail_read

a message, a whole conversation (thread: true, iCloud included, sent replies too), or a draft with its revision; attachment IDs

mail_get_attachment

base64, up to 20 MiB

mail_create_draft

a new message, a reply (replyTo) or a forward (forward, with attachments); saved signatures added

mail_update_draft

merge update, given the current revision

mail_send

a draft as saved, given its current revision

mail_list_drafts, mail_delete_draft

mail_update

read, flag, Gmail labels, and moves to inbox, archive, junk, trash or a folder

mail_list_folders, mail_manage_folder

iCloud mailboxes and Gmail labels

mail_settings

primary address, iCloud sending addresses, display names, signatures

mail_health_check

every account's sign-in, sending nothing

Related MCP server: Errol-Mail

Data

Account passwords and preferences are Worker secrets, uploaded by scripts/setup-worker.mjs from this Mac's iCloud configuration (see docs/WORKER.md). The primary address, sending addresses, signatures and display names live in the Worker's KV, seeded on first use and edited from chat. iCloud has no API for its alias settings, so mail_settings adds addresses found in Sent and suggests custom-domain recipients from the inbox.

Drafts live on iCloud: each managed draft carries its ID in a header, so every client sees the same drafts, revisions and send state.

Develop

corepack enable
pnpm install --frozen-lockfile
pnpm test
pnpm test:worker

src/worker/index.ts is the Worker: OAuth, the account-linking pages (accounts.ts), attachment uploads (uploads.ts) and the MailSession Durable Object (session.ts) that serves MCP. src/mcp/server.ts combines the iCloud tools (src/icloud/) with the Gmail and Calendar tools (src/google/). The IMAP, SMTP, MIME and draft modules are under src/services/.

pnpm test:worker runs the Worker in local workerd and walks the OAuth flow a claude.ai connector performs. Real IMAP integration tests run against GreenMail with RUN_IMAP_IT=1 pnpm test:imap.

Attribution

The transport, MIME, and draft modules derive from sweetrb/apple-mail-mcp, under the MIT license. The original copyright notice is preserved in LICENSE.

Available Tools

61 tools
batch-delete-messagesA

Use when: deleting multiple messages in one call (1–100 ids; moves them to Trash). Returns: counts of how many were deleted and how many failed. Do not use when: deleting just one (use delete-message) or filing messages away (use batch-move-messages). Safety: destructive and applies to many messages at once — require explicit user confirmation, and search-messages/list-messages first to confirm every id is correct before deleting.

Inputs: ids (required). Returns: ok, failed, mailbox, success

batch-flag-messagesA

Use when: flagging multiple messages (1–100 ids) in one call, optionally with a color (red/orange/yellow/green/blue/purple/gray). Returns: counts of how many were flagged and how many failed. Do not use when: flagging just one (use flag-message) or removing flags (use batch-unflag-messages). Get the ids from search-messages or list-messages first. Note: flag colors are applied via Mail.app (AppleScript); any IMAP-routed ids in the batch are flagged but not colored (IMAP flags are colorless).

Inputs: ids (required), color. Returns: ok, failed, mailbox, success

batch-mark-as-readA

Use when: marking multiple messages (1–100 ids) as read in one call. Returns: counts of how many were marked read and how many failed. Do not use when: marking just one (use mark-as-read) or marking unread (use batch-mark-as-unread). Get the ids from search-messages or list-messages first.

Inputs: ids (required). Returns: ok, failed, mailbox, success

batch-mark-as-unreadA

Use when: marking multiple messages (1–100 ids) as unread in one call. Returns: counts of how many were marked unread and how many failed. Do not use when: marking just one (use mark-as-unread) or marking read (use batch-mark-as-read). Get the ids from search-messages or list-messages first.

Inputs: ids (required). Returns: ok, failed, mailbox, success

batch-move-messagesA

Use when: moving multiple messages (1–100 ids) into the same destination mailbox/folder in one call, e.g. bulk archiving. Returns: counts of how many were moved and how many failed. Do not use when: moving just one (use move-message) or deleting (use batch-delete-messages). Use list-mailboxes to confirm the destination name exists. Safety: moves many real messages at once — confirm the destination mailbox, and search-messages/list-messages first to confirm the ids.

Inputs: ids (required), mailbox (required), account. Returns: ok, failed, mailbox, success

batch-unflag-messagesA

Use when: removing flags from multiple messages (1–100 ids) in one call. Returns: counts of how many were unflagged and how many failed. Do not use when: unflagging just one (use unflag-message) or adding flags (use batch-flag-messages). Get the ids from search-messages or list-messages first.

Inputs: ids (required). Returns: ok, failed, mailbox, success

cancel-scheduled-sendA

Use when: preventing one pending Apple Mail scheduled send after the user explicitly confirms the exact schedule_id. Returns: the cancelled schedule and leaves the original draft in Drafts. Do not use when: the job is already sending or terminal. Safety: cancellation prevents a future external action; require explicit confirmation before passing confirmed=true.

Inputs: confirmed (required), schedule_id (required). Returns: ok, schedule

create-draftA

Use when: composing an email the user should review in Mail.app before sending — the safe default for any new message. Select a concrete From alias with from after list-sending-identities; account remains as a backwards-compatible account/identity selector. Returns: the stable draft_id, actual From identity, recipients, subject, and attachment count. Do not use when: editing an existing draft (use update-draft) or the user wants it sent now (use send-email). Safety: creates and saves a draft only; it sends nothing.

Inputs: to (required), body (required), subject (required), cc, +4 more. Returns: ok, from, subject, draft_id, +2 more

create-mailboxA

Use when: creating a new mailbox/folder in an account. Returns: a confirmation that the mailbox was created. Do not use when: renaming an existing one (use rename-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to see what already exists. Safety: creates a real folder in the mail account — confirm the name and target account first.

Inputs: name (required), account. Returns: ok, name

create-newsletter-smart-mailboxesA

Use when: auto-discovering newsletter/bulk senders in your INBOX(es) and (optionally) creating a dedicated smart mailbox per sender (named "NL: "). Defaults to a safe dry run that only proposes. Returns: the proposed or created smart mailboxes with their match scores. Do not use when: you already know the exact sender (use create-smart-mailbox) or want real folders (use create-mailbox). Safety: with dryRun=false it edits Apple Mail's SyncedSmartMailboxes.plist (backed up, atomic, existing entries preserved) and can create many smart mailboxes at once — review a dryRun first. It scans up to ~400 recent messages per inbox via AppleScript, which can be slow on large mailboxes.

Inputs: days, dryRun, minCount. Returns: count, dryRun

create-ruleA

Use when: creating a new Mail rule with one or more conditions (field/operator/value) and at least one action (markRead, markFlagged, delete, or moveTo). Set matchAll to require all conditions vs. any. Returns: a confirmation naming the rule and its condition count. Do not use when: toggling an existing rule (use enable-rule / disable-rule) or removing one (use delete-rule). Use list-rules to avoid duplicating an existing rule. Safety: creates a rule that automatically acts on real mail (including delete/move actions) on an ongoing basis — confirm the conditions and actions with the user before calling.

Inputs: name (required), actions (required), conditions (required), enabled, +1 more. Returns: name, created

create-smart-mailboxA

Use when: creating an Apple Mail smart mailbox (a criteria-based virtual view) that matches a sender, subject, or body substring — works on German-localized macOS where AppleScript's smart-mailbox terms fail. Returns: confirmation of creation, or a note that a smart mailbox with that name already existed. Do not use when: creating a real folder (use create-mailbox). Safety: edits Apple Mail's SyncedSmartMailboxes.plist directly. It backs the file up (.bak) and writes atomically, and never rewrites your existing smart mailboxes. It does not quit Mail — quit Mail first for reliable results, since a running Mail may not show the new smart mailbox until relaunched and can overwrite plist edits it did not make.

Inputs: name (required), bodyContains, fromContains, subjectContains. Returns: ok, name, alreadyExisted

delete-draftA

Use when: moving one inspected Apple Mail draft to Trash by its draft_id. The connector locates the exact saved Drafts mailbox message by account, mailbox, and native message id. Returns: the deleted draft_id and subject. Do not use when: deleting ordinary mail (use delete-message). Safety: destructive — require explicit user confirmation of this exact draft_id after read-draft.

Inputs: draft_id (required). Returns: ok, subject, draft_id

delete-mailboxA

Use when: deleting a mailbox/folder from an account. Returns: a confirmation that the mailbox was deleted. Do not use when: renaming it (use rename-mailbox) or deleting messages within it (use delete-message / batch-delete-messages). Safety: destructive — deleting a mailbox removes the folder and any messages it contains. Require explicit user confirmation and use list-mailboxes first to confirm the exact name.

Inputs: name (required), account. Returns: ok, name

delete-messageA

Use when: deleting a single message by id (moves it to Trash). Returns: a confirmation that the message was deleted. Do not use when: deleting several at once (use batch-delete-messages) or just filing it away (use move-message). Safety: destructive — require explicit user confirmation, and search-messages/list-messages first to confirm you have the right id before deleting.

Inputs: id (required). Returns: id, ok

delete-ruleA

Use when: permanently removing a Mail rule by name. Returns: a confirmation that the rule was deleted. Do not use when: you only want to pause it (use disable-rule) or create one (use create-rule). Safety: destructive — the rule is removed permanently. Require explicit user confirmation and use list-rules first to confirm the exact name.

Inputs: name (required). Returns: name, deleted

delete-smart-mailboxA

Use when: deleting an Apple Mail smart mailbox (virtual view) by name. Returns: confirmation of deletion. Do not use when: deleting a real folder (use delete-mailbox) or messages (use delete-message / batch-delete-messages). Safety: destructive — removes the smart mailbox from Apple Mail's SyncedSmartMailboxes.plist. It backs the file up (.bak) and writes atomically, preserving every other smart mailbox, but the removal is not undoable in-app. Confirm the exact name with list-smart-mailboxes first, and quit Mail first for reliable results.

Inputs: name (required). Returns: ok, name

delete-templateA

Use when: permanently removing a saved email template by id. Returns: a confirmation that the template was deleted. Do not use when: you only want to view it (use get-template) or update it (use save-template with the existing id). Safety: destructive — removes the template from the on-disk store permanently. Require explicit user confirmation and use list-templates first to confirm the id.

Inputs: id (required). Returns: id, ok

disable-ruleA

Use when: turning off an existing Mail rule by name (without deleting it). Returns: a confirmation that the rule was disabled. Do not use when: turning a rule on (use enable-rule), creating one (use create-rule), or removing it permanently (use delete-rule). Use list-rules to confirm the exact rule name.

Inputs: name (required). Returns: ok, name, enabled

doctorA

Use when: troubleshooting setup problems — diagnoses Mail.app automation permissions, account state, and the IMAP/SMTP backends with actionable remediation messages. Returns: a detailed diagnostic report (formatted text plus structured checks). Do not use when: you just want a quick up/down status (use health-check) or message counts (use get-mail-stats).

Inputs: no named parameters. Returns: checks, healthy

enable-ruleA

Use when: turning on an existing Mail rule by name. Returns: a confirmation that the rule was enabled. Do not use when: turning a rule off (use disable-rule), creating one (use create-rule), or deleting one (use delete-rule). Use list-rules to confirm the exact rule name.

Inputs: name (required). Returns: ok, name, enabled

fetch-attachmentA

Use when: retrieving an attachment's raw bytes inline as base64 (by message id and attachmentName), e.g. to process its contents without touching disk. Returns: the attachment's bytes base64-encoded, with its size and (for IMAP) MIME type. Do not use when: you don't know the attachment name (use list-attachments first) or you just want it saved to disk (use save-attachment).

Inputs: id (required), attachmentName (required). Returns: bytes, mimeType, contentBase64, attachmentName

flag-messageA

Use when: flagging a single message (by id), optionally with a color (red/orange/yellow/green/blue/purple/gray). Returns: a confirmation that the message was flagged (and the color, when applied). Do not use when: flagging several at once (use batch-flag-messages) or removing a flag (use unflag-message). Get the id from search-messages or list-messages first. Note: flag colors are a Mail.app feature applied via AppleScript; for an IMAP-routed id the flag is set but the color is not applied (IMAP flags are colorless).

Inputs: id (required), color. Returns: id, ok, color, colorApplied

forward-messageA

Use when: forwarding an existing message (by id) to new recipients (to is an array), with an optional body to prepend. Set send=false to save as a draft. Returns: a confirmation that the message was forwarded or saved as a draft. Do not use when: replying to the sender/recipients (use reply-to-message) or composing a new message (use send-email / create-draft). Safety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and any prepended body, or pass send=false to let the user review.

Inputs: id (required), to (required), body, send. Returns: id, ok, sent, recipients

get-mail-statsA

Use when: you want aggregate mailbox statistics — total and unread message counts, recently-received counts (last 24h/7d/30d), and (for the all-accounts path) a per-account breakdown. Returns: totals, unread counts, recent-activity counts, and per-account figures. Do not use when: you only need a single unread number (use get-unread-count) or want to list the messages themselves (use list-messages / search-messages).

Inputs: account. Returns: recent, account, accounts, totalUnread, +2 more

get-messageA

Use when: reading the full body of one message whose id you already have (numeric or imap:…); set preferHtml to get the HTML body instead of plain text. Returns: the message subject, body (plain text by default, HTML when preferHtml is true), and its stable RFC Message-ID (rfcMessageId) for dedup/threading. Tip: pass the mailbox+account you got the id from (e.g. from search-messages) to fetch it directly — required for reliable reads of large folders like "Sent Items", which otherwise time out. Do not use when: you don't yet have an id (use search-messages or list-messages first), or you want the whole conversation (use get-thread).

Inputs: id (required), account, mailbox, preferHtml. Returns: id, body, isHtml, subject, +1 more

get-sync-statusA

Use when: checking whether Mail.app is running and actively syncing, e.g. to explain why new mail hasn't appeared yet. Returns: whether Mail.app is running and whether sync activity was detected. Do not use when: you need message counts (use get-mail-stats) or a full setup diagnosis (use doctor).

Inputs: no named parameters. Returns: error, syncDetected, pendingUpload, recentActivity, +1 more

get-templateA

Use when: reading the full contents of one saved template by id — its name, subject, default to/cc, and body. Returns: the template's name, subject, default recipients, and body text. Do not use when: you don't have the id (use list-templates first) or want to apply the template into a draft (use use-template).

Inputs: id (required). Returns: cc, id, to, body, +2 more

get-threadA

Use when: you have one message id and want the whole conversation it belongs to, oldest-first. With an imap: id it threads by References/Message-ID; otherwise it groups by normalized subject. Returns: the thread's normalized subject and its messages (id, date, subject, sender, read state). Do not use when: you only need the single message (use get-message) or are searching by arbitrary criteria (use search-messages).

Inputs: id (required), limit, account, mailbox. Returns: count, partial, subject, messages

get-unread-countA

Use when: you only need the number of unread messages — INBOX by default, or scoped to one mailbox and/or account — without listing the messages themselves. Returns: the unread count for the requested scope (INBOX when no mailbox is given). Do not use when: you need the actual unread messages and their ids (use list-messages with unreadOnly, or search-messages with isRead=false) or broader totals across every mailbox (use get-mail-stats).

Inputs: account, mailbox. Returns: unread, account, mailbox

health-checkA

Use when: doing a quick check that Mail.app is reachable and the server's basic checks pass. Returns: an overall healthy/unhealthy status with a pass/fail line per check. Do not use when: you need detailed permission/account/IMAP/SMTP diagnostics with remediation steps (use doctor).

Inputs: no named parameters. Returns: checks, healthy

list-accountsA

Use when: discovering the configured Mail accounts (e.g. iCloud, Gmail) so you can pass an exact account name to other tools. Returns: the account names and a count. Do not use when: you want the folders within an account (use list-mailboxes) or messages (use list-messages / search-messages).

Inputs: no named parameters. Returns: count, accounts

list-attachmentsA

Use when: enumerating a message's attachments (by id) to discover their names, MIME types, and sizes — typically before saving or fetching one. Returns: each attachment's name, MIME type, and size, plus a count. Do not use when: you want the bytes (use fetch-attachment for inline base64, or save-attachment to write to disk). Get the message id from search-messages or list-messages first.

Inputs: id (required). Returns: count, attachments

list-draftsA

Use when: reviewing or selecting saved Apple Mail drafts before reading, editing, sending, or deleting one. This reads every account's actual Drafts mailbox, not just currently open compose windows. Returns: Gmail-like draft resources with stable draft_id, actual From identity, recipients, subject, attachment status, and a short body preview. Do not use when: browsing ordinary mailbox messages (use list-messages).

Inputs: limit. Returns: count, drafts

list-mailboxesA

Use when: discovering the mailbox/folder names (and unread/message counts) available in an account, e.g. before moving messages or searching a specific mailbox. Returns: each mailbox's name with its unread (and, for IMAP, total message) count, plus a count. Do not use when: you want the messages inside a mailbox (use list-messages or search-messages) or the list of accounts (use list-accounts).

Inputs: account. Returns: count, mailboxes

list-messagesA

Use when: browsing a mailbox's recent messages (optionally filtered by sender or unread-only) with pagination via limit/offset, and you need their ids. Returns: messages with id, date, subject, and sender (plus partial-coverage diagnostics when some mailboxes were skipped). Do not use when: you have specific search criteria like subject/date/flags (use search-messages) or already have an id and want the body (use get-message). Like search-messages, use this to obtain the ids that read/mark/delete/move and batch tools require.

Inputs: from, limit, offset, account, +2 more. Returns: count, partial, messages, timedOutAccounts, +2 more

list-rulesA

Use when: discovering the Mail rules that exist and whether each is enabled or disabled, e.g. before enabling/disabling/deleting one. Returns: each rule's name and enabled/disabled state. Do not use when: you want to change a rule (use enable-rule / disable-rule / create-rule / delete-rule).

Inputs: no named parameters. Returns: count, rules

list-scheduled-sendsA

Use when: reviewing future Apple Mail sends, checking whether scheduled drafts were sent, or diagnosing a failed/needs_review job. Returns: schedule IDs, draft IDs, requested/UTC send times, status, From, recipients, subject, and any error. Do not use when: listing ordinary drafts (use list-drafts). This is read-only.

Inputs: status. Returns: count, schedules

list-sending-identitiesA

Use when: discovering the concrete From addresses/aliases configured in Apple Mail before creating, editing, or sending mail. Accounts and sending identities are different resources: one account can expose several aliases. Returns: identity_id, account, email, formatted sender, enabled state, and default state for every configured identity. Do not use when: you only need receiving-account names (use list-accounts).

Inputs: no named parameters. Returns: count, identities, default_identity_id

list-smart-mailboxesA

Use when: listing Apple Mail smart mailboxes (criteria-based virtual views), including on German-localized macOS where AppleScript's smart-mailbox terms do not compile. Returns: each smart mailbox's name and a short criteria summary. Do not use when: listing real folders/mailboxes (use list-mailboxes).

Inputs: no named parameters. Returns: count, smartMailboxes

list-templatesA

Use when: discovering the saved email templates and their ids, e.g. before using or editing one. Returns: each template's id, name, and subject. Do not use when: you want a single template's full body (use get-template) or want to apply one (use use-template).

Inputs: no named parameters. Returns: count, templates

mark-as-readA

Use when: marking a single message (by id) as read. Returns: a confirmation that the message was marked read. Do not use when: marking several at once (use batch-mark-as-read) or marking unread (use mark-as-unread). Get the id from search-messages or list-messages first.

Inputs: id (required). Returns: id, ok

mark-as-unreadA

Use when: marking a single message (by id) as unread. Returns: a confirmation that the message was marked unread. Do not use when: marking several at once (use batch-mark-as-unread) or marking read (use mark-as-read). Get the id from search-messages or list-messages first.

Inputs: id (required). Returns: id, ok

move-messageA

Use when: moving a single message (by id) into another mailbox/folder, e.g. archiving or filing. Returns: a confirmation naming the destination mailbox. Do not use when: moving several at once (use batch-move-messages) or deleting (use delete-message). Use list-mailboxes to confirm the destination name exists. Safety: moves a real message between folders — confirm the destination mailbox, and search-messages/list-messages first to confirm the id.

Inputs: id (required), mailbox (required), account. Returns: id, ok, mailbox

read-draftA

Use when: reading the full current contents of one draft selected from list-drafts. Returns: the stable draft_id, actual From identity, recipients, subject, and full body. Do not use when: you only need draft summaries (use list-drafts).

Inputs: draft_id (required). Returns: draft

rename-mailboxA

Use when: renaming an existing mailbox/folder from oldName to newName within an account. Returns: a confirmation naming the old and new mailbox names. Do not use when: creating a new folder (use create-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to confirm the current name. Safety: renames a real folder in the mail account — confirm oldName matches exactly (case-sensitive) before calling.

Inputs: newName (required), oldName (required), account. Returns: ok, newName, oldName

reply-to-messageA

Use when: replying to an existing message by id, preserving its threading headers. Set replyAll for all recipients; set send=false to save as a draft instead of sending. Returns: a confirmation that the reply was sent or saved as a draft. Do not use when: composing a brand-new message (use send-email / create-draft) or forwarding to new recipients (use forward-message). Safety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and body, or pass send=false to let the user review.

Inputs: id (required), body (required), send, replyAll. Returns: id, ok, sent

reschedule-scheduled-sendA

Use when: changing the future time of one pending Apple Mail scheduled send after the user explicitly confirms the schedule_id and new timezone-aware time. Returns: the updated schedule. Do not use when: the job is already sending, sent, failed, cancelled, or needs_review. Safety: changes when a real email will be sent; require explicit confirmation before passing confirmed=true.

Inputs: send_at (required), confirmed (required), schedule_id (required). Returns: ok, schedule

resolve-message-idA

Use when: you have imap: message id(s) and need the numeric Mail.app id(s) — most importantly to apply a flag COLOR, which only sticks on the AppleScript numeric-id path (IMAP \Flagged is colorless, so a smart mailbox keyed on flag color never matches an IMAP-flagged message). Each imap: id is resolved via its RFC822 Message-ID. Returns: for each input id, its numericId (the AppleScript id) or null when it can't be resolved, plus the messageId used; and a resolvedCount. Do not use when: your ids are already numeric (they pass straight through), or you don't need a color — flag/move/mark tools operate on imap: ids directly.

Inputs: ids (required). Returns: count, resolved, resolvedCount

save-attachmentA

Use when: writing one of a message's attachments to disk, by message id and attachmentName, into the savePath directory (saved as savePath/attachmentName). Returns: a confirmation of the saved file path. Do not use when: you don't know the attachment name (use list-attachments first) or want the bytes inline rather than on disk (use fetch-attachment). Safety: writes a file to disk — savePath must be a directory inside the configured allowed roots, and attachmentName may not contain path separators or '..'; calls outside those constraints are rejected.

Inputs: id (required), savePath (required), attachmentName (required). Returns: ok, savedPath, attachmentName

save-templateA

Use when: creating a reusable email template (name, subject, body, optional default to/cc), or updating one by passing its existing id. Subject/body may contain placeholders for later use. Returns: the saved template's name and id (reuse the id with use-template / get-template / delete-template). Do not use when: composing a one-off message (use create-draft / send-email) or filling in a template to send (use use-template). Safety: writes the template to the on-disk templates store (APPLE_MAIL_MCP_TEMPLATES_FILE) and persists across restarts; passing an existing id overwrites that template.

Inputs: body (required), name (required), subject (required), cc, +2 more. Returns: id, ok, name

schedule-draftsA

Use when: the user explicitly asks to send one or more fully reviewed Apple Mail drafts at a future date/time. Returns: one persistent schedule_id per draft, the exact requested time, recipients, From identity, subject, and pending status. Requirements: send_at must be RFC 3339 with an explicit timezone offset (for example 2026-07-29T07:00:00+08:00); drafts with attachments are refused; the Mac must remain logged in, and overdue jobs run after wake/login. Do not use when: the user merely mentions a possible future send, has not reviewed the drafts, or wants Mail's native Send Later mailbox—the public Mail scripting API does not expose that UI feature. Safety: this creates a REAL FUTURE SEND. Require explicit confirmation of the exact draft_ids, recipients/content, From identity, send time, and timezone before passing confirmed=true.

Inputs: send_at (required), confirmed (required), draft_ids (required). Returns: ok, count, schedules

search-contactsA

Use when: looking up a person in Contacts by name, organization, nickname, or email to find their email address(es)/phone(s) before composing or sending mail. Reads the macOS Contacts database directly (needs Full Disk Access; does NOT require Contacts.app to be running or an Automation / Apple-Events grant). Returns: matching contacts with their names, email addresses, and phone numbers. Do not use when: searching email messages (use search-messages) — this queries Contacts, not the mailbox.

Inputs: query (required). Returns: count, contacts

search-messagesA

Use when: finding messages by query/sender/subject/date/read/flag filters and you need their ids for follow-up operations. Returns: matching messages with id, date, subject, sender, and read state (plus partial-coverage diagnostics when some mailboxes were skipped). Do not use when: you want a plain mailbox listing without filters (use list-messages), already have an id and want the body (use get-message), or want a whole conversation (use get-thread). Prefer this first to obtain the message ids that get-message/mark-as-read/delete-message/move-message and the batch tools require.

Inputs: from, limit, query, dateTo, +6 more. Returns: count, partial, messages, timedOutAccounts, +2 more

send-draftA

Use when: sending an existing Apple Mail draft after the user has reviewed it or explicitly asked to send that draft. Saved plain-text drafts are reconstructed through Mail's compose bridge; attached drafts must be sent from Mail.app to preserve their MIME structure. Returns: the sent draft_id, subject, actual From identity, and recipients. Do not use when: the user still needs to review or edit it (use read-draft/update-draft), or when has_attachments is true. Safety: SENDS real email immediately and cannot be unsent — require explicit confirmation of this exact draft.

Inputs: draft_id (required). Returns: ok, from, subject, draft_id, +1 more

send-emailA

Use when: the user has explicitly confirmed they want to send a single email now to the given recipients (to/cc/bcc are arrays), optionally with attachments and a chosen transport. Returns: a confirmation naming the recipients and attachment count. Do not use when: the user wants to review first (use create-draft), is replying to or forwarding an existing message (use reply-to-message / forward-message), or wants per-recipient personalized copies (use send-serial-email). Safety: this SENDS real email immediately and it cannot be unsent — require explicit user confirmation of the exact recipients, subject, and body before calling. Prefer create-draft when there is any doubt.

Inputs: to (required), body (required), subject (required), cc, +4 more. Returns: ok, transport, recipients, attachmentCount

send-serial-emailA

Use when: the user has confirmed a mail-merge — sending individually personalized copies to many recipients (max 100), with {{Key}} placeholders in subject/body replaced per-recipient from each recipient's variables. Recipients do not see each other. Returns: a per-recipient sent/failed report with counts. Do not use when: sending one message to a shared recipient list (use send-email) or saving for review (use create-draft). Safety: this SENDS many real emails immediately and they cannot be unsent — require explicit user confirmation of the recipient list, the subject/body template, and the placeholder substitutions before calling.

Inputs: body (required), subject (required), recipients (required), account, +1 more. Returns: ok, sent, failed, results

set-default-sending-identityA

Use when: choosing the plugin's default From identity for future create-draft calls. This changes only apple-mail-mcp's local preference; it does not alter Mail.app account settings. Returns: the selected identity. Do not use when: selecting From for only one draft (pass from to create-draft/update-draft). Safety: writes a reversible local preference and sends nothing.

Inputs: identity (required). Returns: ok, identity

unflag-messageA

Use when: removing the flag from a single message (by id). Returns: a confirmation that the message was unflagged. Do not use when: unflagging several at once (use batch-unflag-messages) or adding a flag (use flag-message). Get the id from search-messages or list-messages first.

Inputs: id (required). Returns: id, ok

update-draftA

Use when: editing an existing Apple Mail draft in place, selected by draft_id from list-drafts. Omitted fields are preserved; empty recipient arrays explicitly clear that recipient class. Mail's scripting bridge cannot safely recreate attached drafts, so update-draft refuses them instead of losing attachments. Returns: the same stable draft_id and the complete updated draft. Do not use when: creating a new draft (use create-draft), or when has_attachments is true (edit that draft in Mail.app). Safety: updates a saved draft only and sends nothing.

Inputs: draft_id (required), cc, to, bcc, +3 more. Returns: ok, draft

use-templateA

Use when: composing a new draft from a saved template (by id), optionally overriding the recipients, subject, or body. Creates a draft in Mail.app for the user to review and send. Returns: a confirmation that a draft was created from the template. Do not use when: you want to inspect the template without composing (use get-template) or send immediately without a draft (use send-email).

Inputs: id (required), cc, to, body, +1 more. Returns: id, ok

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 61 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action, with detailed 'use when' and 'do not use when' guidance that clearly differentiates similar-sounding tools like send-email vs send-serial-email vs send-draft, or search-messages vs list-messages. No two tools overlap in purpose.

    Naming Consistency5/5

    All 61 tools follow a consistent verb_noun snake_case pattern (e.g., delete-template, list-messages, batch-flag-messages). The naming is uniform and predictable, making it easy to infer tool behavior from its name.

    Tool Count2/5

    With 61 tools, the count is far above the typical well-scoped range of 3-15. While each tool has a clear purpose, the high number—especially the proliferation of batch variants and diagnostic tools—makes the surface feel bloated and potentially overwhelming for an agent.

    Completeness5/5

    The tool set covers virtually every aspect of email management: sending, receiving, drafting, replying, forwarding, mailbox CRUD, rule management, template management, smart mailboxes, contacts, attachments, scheduling, and diagnostics. There are no obvious gaps for a consumer email client.

    Maintenance

    ActivityActive
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      A
      maintenance
      This MCP server allows AI assistants to read, send, search, and manage emails in Apple Mail on macOS. It uses AppleScript to interact with the Mail app locally.
      52
      4,105 npm
      107
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that gives AI assistants comprehensive access to Apple Mail accounts, enabling email discovery, reading, flag management, and server-side message retrieval.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      An MCP server that provides programmatic access to Apple Mail, enabling AI assistants like Claude to read, send, search, and manage emails on macOS.
      25
      MIT