servers / apple-mail-fast-mcp

apple-mail-fast-mcp

communitystdiolocaldestructive capablehealthy

🤖 MCP server for Apple Mail - Manage emails with AI using Claude Desktop. Search, send, organize mail with natural language.


01Tools · 24

How to read this: tool names here are observed from a live tools/list handshake. The Risk label is a heuristic inferred from the tool name (write/destructive verbs), not from executing the tool — a conservative guess, not a verified capability. We never escalate risk from a description. Found one that's wrong? Tell us — we fix on report.

ToolRiskSide effectsApproval
list_accounts
List all configured email accounts in Apple Mail. Returns each account's id (UUID), display name, email addresses, account type, and enabled state. Account ids are stable across name changes; prefer them over names for identifying accounts. Returns: Dictionary containing the accounts list. Example: >>> list_accounts() {"success": True, "accounts": [ {"id": "B21B254B-...", "name": "Gmail", "email_addresses": ["me@gmail.com"], "account_type": "imap", "enabled": True}, ... ]}
readfalseunknown
update_rule
Update an existing Mail.app rule (patch semantics). Patch semantics: only fields you provide are changed. ``conditions`` and ``actions``, when provided, REPLACE their respective structures wholesale (not merged). Conditional confirmation: prompts the user via MCP elicitation when the patch touches ``conditions`` or ``match_logic`` (which alter matching scope), or replaces ``actions`` with a set that includes a dangerous action (move / forward / delete / copy). An ``actions`` patch limited to organizational flags (``mark_read`` / ``mark_flagged`` / ``flag_color``) skips the prompt, as do patches limited to ``enabled`` and/or ``name`` (trivially reversible). The enable/disable path replaces the removed ``set_rule_enabled`` tool: call ``update_rule(rule_index, enabled=True|False)``. Refuses to update any rule whose existing actions include something outside the supported schema (run-AppleScript, redirect, reply text, play sound, custom highlight color); raises MailUnsupportedRuleActionError. Edit such rules in Mail.app's UI.
writetrueunknown
list_rules
List all Mail.app rules (read-only). Returns each rule's display name and enabled state. Rule names are NOT guaranteed unique — Mail allows duplicates — and rules have no stable id via AppleScript. This tool is read-only; mutation (enable/disable, create, delete) is tracked as a separate enhancement. Returns: Dictionary containing the rules list. Example: >>> list_rules() {"success": True, "rules": [ {"name": "Junk filter", "enabled": True}, {"name": "News From Apple", "enabled": False}, ... ], "count": 2}
readfalseunknown
list_mailboxes
List all mailboxes for an account.
readfalseunknown
get_thread
Return all messages in the thread containing the given message. Looks up the anchor message by its id, then reconstructs the conversation via the connector's tiered IMAP threading dispatch (Tier 1 X-GM-THRID for Gmail, Tier 3 header-search BFS fallback) or the AppleScript path. Result rows are sorted by ``date_received`` ascending. The returned ids can be piped into ``search_messages(source=[ids])`` for filtered metadata or ``get_messages([ids])`` for full bodies. Known limitation: thread members whose subject was rewritten mid-conversation are missed on the AppleScript fallback path (subject prefilter tradeoff).
readfalseunknown
delete_rule
Delete a Mail.app rule by 1-based positional index. Destructive — requires user confirmation via MCP elicitation before running. Cannot be undone (Mail.app does not version rule history).
destructivetruetrue
search_messages
Search for messages matching criteria. Returns metadata-only rows. Two corpus modes: - ``source=None`` (default): search the given account/mailbox using the IMAP/AppleScript SEARCH path. ``account`` is required. - ``source=[id1, id2, ...]``: scope the search to the specific messages identified by the given ids. ``account``/``mailbox`` are ignored; the connector resolves each id self-sufficiently. The resulting message dicts are post-filtered by the other criteria (``sender_contains``, ``read_status``, etc.) — full filter composition. The literal token ``"SELECTED"`` may appear in the list and is server-resolved at call time to Mail.app's current UI selection (zero-or-more messages). Mixed lists like ``["SELECTED", "12345"]`` are valid. Missing ids drop out silently (partial-results). For thread retrieval, call ``get_thread(message_id)`` to expand an anchor into thread member ids, then optionally pipe those ids into ``source=[ids]`` for filtered metadata browsing or into ``get_messages([ids])`` for full bodies.
readfalseunknown
save_attachments
Save attachments from a message to a directory.
unknownunknownunknown
create_rule
Create a new Mail.app rule. Rules with actions that can move, forward, or delete mail (delete / forward_to / move_to / copy_to) require user confirmation — a single create can install automation that auto-forwards or deletes all future mail (#222). Organizational-only rules (mark_read, mark_flagged, flag_color) are created without a prompt. Mail.app appends new rules to the end of the rule list, so the returned ``rule_index`` equals the new total rule count.
writetrueunknown
get_messages
Get full details of one or more messages, with bodies. Returns a list of message dicts (possibly of length 0 or 1). Pair with ``search_messages`` (metadata-only) and ``get_thread`` (thread member ids) to fetch bodies for specific messages.
readfalseunknown
get_attachment_content
Read one attachment's content inline, without writing it to disk. For "triage" workflows where you want to inspect an attachment (a text file, JSON, a small PDF) before deciding what to do with it — instead of ``save_attachments`` → read the file → clean up.
readfalseunknown
update_message
Update one or more messages: change read state, flag, and/or move, in one atomic call (#135). Patch semantics — caller specifies only the fields to change. All specified mutations apply in a single AppleScript pass via the bulk-update helper. Replaces the previous `mark_as_read`, `move_messages`, and `flag_message` tools. Order of operations (matters for IMAP): read-state and flag changes apply first (in source mailbox), then the move. IMAP requires the message to exist in the source folder for STORE before MOVE.
writetrueunknown
create_mailbox
Create a new mailbox/folder.
writetrueunknown
update_mailbox
Rename and/or re-parent (move) an existing mailbox. Two delivery paths: - **Rename only** (``new_name`` set, ``new_parent`` is ``None``): AppleScript. Fast, no IMAP credentials needed. - **Move** (``new_parent`` set; optionally combined with rename): IMAP RENAME. Requires IMAP credentials in Keychain (#73 opt-in flow) — returns ``error_type: "imap_required"`` when missing. At least one of ``new_name`` / ``new_parent`` must be provided. Refused (#164): operations targeting the bare ``[Gmail]`` parent or any ``[Gmail]/...`` child path return ``error_type: "unsupported_gmail_system_label"``. Applies to both the source ``name`` and the resulting destination (``new_parent`` join). Gmail's IMAP server doesn't support normal RENAME semantics for these paths; user-created Gmail labels (``Newsletters``, etc.) behave normally.
writetrueunknown
delete_mailbox
Delete a mailbox via IMAP. Mail.app's AppleScript dictionary doesn't expose a working delete primitive for mailboxes, so this operation goes through IMAP. Requires IMAP credentials in Keychain (#73 opt-in flow) — returns ``error_type: "imap_required"`` when missing. Always elicits user confirmation (destructive). By default refuses non-empty mailboxes to prevent accidental data loss; pass ``delete_messages=True`` to cascade. Refused (#164): targeting the bare ``[Gmail]`` parent or any ``[Gmail]/...`` child path returns ``error_type: "unsupported_gmail_system_label"``. Gmail's IMAP server doesn't support DELETE for these paths.
destructivetruetrue
save_template
Create or overwrite a template.
unknownunknownunknown
delete_messages
Delete messages (always moves to the account's Trash mailbox). Destructive: gated behind user confirmation via MCP elicitation (issue #239), matching delete_rule / delete_mailbox / delete_template.
destructivetruetrue
delete_template
Delete a template by name. Destructive — requires user confirmation via MCP elicitation before running.
destructivetruetrue
list_templates
List all stored email templates. Templates live as files at ~/.apple_mail_mcp/templates/<name>.md. Override the location with the APPLE_MAIL_MCP_HOME environment variable. Returns: Dictionary with each template's name and subject (or null if no subject header is set).
readfalseunknown
get_template
Read a single template by name.
readfalseunknown
create_draft
Create a draft (fresh, reply, or forward). Optionally send immediately. Mail.app's actual primitive is the draft — every outgoing message is a draft until sent. This tool lets callers create one, optionally seeded from an existing message (reply or forward), and either save it for later or send it now.
writetrueunknown
render_template
Render a template into ready-to-send subject and body text. No side effects — caller is responsible for passing the rendered text to ``create_draft`` or ``update_draft`` (with ``send_now=True`` when ready to send). With ``message_id``, the original sender's display name and email, the original subject, and today's date are auto-populated as ``recipient_name``, ``recipient_email``, ``original_subject``, and ``today``. Without ``message_id``, only ``today`` is auto-filled. User-supplied ``vars`` always override auto-fills on conflict.
unknownunknownunknown
update_draft
Update an existing draft. Implemented as delete-and-recreate. **Returns a NEW draft_id** — Mail.app forbids mutating saved drafts, so update is implemented by reading the draft's current state, deleting it, and creating a new draft with the merged fields. Threading headers (for reply seeds) and forward anchor are preserved via persisted seed metadata. Field merge semantics: any non-None argument overrides the existing value. ``None`` keeps the existing value. ``attachment_paths=None`` PRESERVES existing attachments (extracted via Mail's ``save`` command); ``[]`` explicitly clears them; a list replaces. For drafts created externally (not via ``create_draft``), seed recovery falls back to scanning Mail.app for the In-Reply-To header — this can be slow on large mailboxes (~30s+ per call). Forward seeds without disk state are misclassified as fresh; pass an explicit body if so.
writetrueunknown
delete_draft
Delete (move to Trash) an existing draft. Lifecycle endpoint for cancellation. Mail.app moves the message to the Deleted Messages mailbox; recovery is technically possible but Mail.app no longer treats trashed drafts as editable, so this is effectively a one-way discard. No elicitation (recoverable from Trash) and no rate limit (local operation).
destructivetruetrue

02Install & source
uvx apple-mail-fast-mcp
uvx

03Access granted
Read email · destructive

The access this server can exercise, inferred from its verified tools — not a declared OAuth scope.


05Provenance & freshness
sourcesGitHub repo search [p4]
last_checked2026-08-01 13:42Z
next_check2026-08-02 06:55Z
cadenceevery 17h
verifiedtools_list:passed handshake:passed metadata:passed metadata:passed
index_statusindex — 9 unique facts >= 5

06Badge

Add the “as seen on MCPExplorer” badge to your README. apple-mail-fast-mcp MCP — as seen on mcpexplorer.com

[![apple-mail-fast-mcp MCP — as seen on mcpexplorer.com](https://mcpexplorer.com/badge/apple-mail-fast-mcp.svg)](https://mcpexplorer.com/servers/apple-mail-fast-mcp)

Next step

This is one server. A loadout combines the right servers, governance, and proven plays for a whole job — assembled deliberately, not tool-dumped.

Explore loadouts →
apple-mail-fast-mcp — MCPExplorer