Apple Mail MCP Server
This MCP server lets AI assistants manage Apple Mail on macOS—read, search, compose, organize, analyze, and export email.
Read and list accounts, inboxes, mailboxes, recent emails, unread counts, threads, and full email content
Search by subject, sender, recipient, body, dates, read/flag status, attachments, across accounts/mailboxes with pagination
Compose, reply/reply-all, forward, create/manage drafts, and build rich HTML drafts with optional attachments
Move, archive, mark read/unread, flag/unflag, delete, empty trash, create mailboxes, and batch-organize mail with dry-run/safety limits
List and save attachments
Analyze inbox stats, top senders, newsletters, awaiting replies, needs-response emails, and dashboards
Export emails to TXT/HTML
Use IMAP-assisted sorting/bulk moves and synchronize accounts
Support read-only mode, configurable preferences, and file-access safeguards
Provides AI assistants with full access to Apple Mail, including reading, searching, composing, organizing, and analyzing emails through natural language.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Apple Mail MCP Server show me my unread emails from today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Apple Mail MCP Server
Star History
An MCP server that gives AI assistants full access to Apple Mail -- read, search, compose, organize, and analyze emails via natural language. Built with FastMCP.
Related MCP server: cloudflare-email
Quick Install
Prerequisites: macOS with Apple Mail configured, Python 3.10+
Claude Code Plugin (Recommended)
Two commands — gets you the MCP server, /email-management slash command, and the Email Management Expert skill:
claude plugin marketplace add patrickfreyer/apple-mail-mcp
claude plugin install apple-mail@apple-mail-mcpThen restart Claude Code.
Other Install Methods
claude mcp add apple-mail -- uvx mcp-apple-mailOr for Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"apple-mail": {
"command": "uvx",
"args": ["mcp-apple-mail"]
}
}
}pip install mcp-apple-mail
claude mcp add apple-mail -- mcp-apple-mailInstalls the Email Management Expert skill via the open skills CLI. The skill does not include the MCP server, so install that too (e.g. with uvx above):
npx skills add patrickfreyer/apple-mail-mcp
claude mcp add apple-mail -- uvx mcp-apple-mailAdd -g to install the skill globally, or -a <agent> to target a specific agent.
Download the latest
apple-mail-mcp-vX.Y.Z.mcpbfrom ReleasesOpen Claude Desktop → Settings → Developer → MCP Servers → Install from file
Select the
.mcpbfile and grant Mail.app permissions
git clone https://github.com/patrickfreyer/apple-mail-mcp.git
cd apple-mail-mcp/plugin
python3 -m venv venv
venv/bin/pip install -r requirements.txt
claude mcp add apple-mail -- /bin/bash $(pwd)/start_mcp.shTools (23)
Reading & Search
Tool | Description |
| Dashboard with unread counts, folders, and recent emails |
| List emails with account/read-status filtering and optional content preview |
| Unread counts per mailbox or per-account summary |
| List all configured Mail accounts |
| Unified search — subject, sender, body text, dates, attachments, flag status/color, cross-account |
| Read one message by numeric id — headers, capped plain-text body and attachment metadata (text or JSON) |
| Conversation thread view |
Organization
Tool | Description |
| Folder hierarchy with message counts |
| Create new mailboxes (supports nested paths) |
| Move/archive emails with filters (subject, sender, date, read status, dry-run) |
| Mark read/unread, flag/unflag (optional flag color) — by filters or message IDs |
| Soft delete, permanent delete, empty trash (with dry-run) |
Composition
Tool | Description |
| Send new emails (plain text or HTML body) |
| Reply or reply-all with optional HTML body |
| Forward with optional message, CC/BCC |
| Create, list, send, and delete drafts |
| Build a rich HTML |
Attachments
Tool | Description |
| List attachments with names and sizes |
| Save attachments to disk |
Smart Inbox
Tool | Description |
| Find sent emails that haven't received a reply |
| Identify emails that likely need your response |
| Analyse most frequent senders by count or domain |
Analytics & Export
Tool | Description |
| Email analytics (volume, top senders, read ratios) |
| Export single emails or mailboxes to TXT/HTML |
| Interactive UI dashboard (requires mcp-ui-server) |
Configuration
Read-Only Mode
Pass --read-only to block delivery. Nothing leaves the machine: compose_email and reply_to_email refuse mode="send", manage_drafts refuses action="send", and forward_email is removed entirely because it has no non-sending mode.
The composing tools stay registered so that mode="draft" and mode="open" keep working. Those never deliver anything, and they are the only place in the compose surface that supports attachments — manage_drafts and create_rich_email_draft cannot attach files.
{
"mcpServers": {
"apple-mail": {
"command": "/path/to/venv/bin/python3",
"args": ["/path/to/apple_mail_mcp.py", "--read-only"]
}
}
}User Preferences (Optional)
Set the USER_EMAIL_PREFERENCES environment variable to give the assistant context about your workflow:
{
"mcpServers": {
"apple-mail": {
"command": "/path/to/venv/bin/python3",
"args": ["/path/to/apple_mail_mcp.py"],
"env": {
"USER_EMAIL_PREFERENCES": "Default to BCG account, show max 50 emails, prefer Archive and Projects folders"
}
}
}
}For .mcpb installs, configure this in Claude Desktop under Developer > MCP Servers > Apple Mail MCP.
Safety Limits
Batch operations have conservative defaults to prevent accidental bulk actions:
Operation | Default Limit |
| 10 emails |
| 5 emails |
| 1 email |
Override via function parameters when needed.
File Access
By default the server can write and attach files anywhere your user account can, except a hardened denylist of locations an attacker could use for code execution or credential theft. (Attachment bytes come from whoever emailed you, and a prompt-injected email can steer tool arguments.)
Writes (save_email_attachment, export_emails, create_rich_email_draft's output_path) are refused for:
any dotfile or dot-folder directly in your home folder: shell startup files (
~/.zshrc,~/.zshenv,~/.zprofile,~/.zlogin,~/.bashrc,~/.bash_profile,~/.profile),~/.ssh,~/.gnupg,~/.aws,~/.config(incl.~/.config/git),~/.gitconfig,~/.netrc,~/.envrc,~/.local/bin, ....git/hooks,.git/configand.envrcin any folderautostart, persistence and app-config folders:
~/Library/LaunchAgents,~/Library/LaunchDaemons,/Library/LaunchAgents,/Library/LaunchDaemons,~/Library/Application Support(incl.com.apple.backgroundtaskmanagementagent),~/Library/Application Scripts,~/Library/Preferences,~/Library/Keychains,~/Library/Mail,~/Library/Containers, ...folders on
PATH:~/bin,/usr/local/bin,/opt/homebrew/bin, and/etc
Attachments (compose_email, reply_to_email, ...) may be any readable file except secrets: ~/.ssh, ~/.gnupg, ~/.aws, ~/.netrc, ~/.git-credentials, ~/.config/gh, .env files, ~/Library/Keychains, and browser profiles and cookie stores (Safari, Chrome, Firefox, Edge, Brave, Arc, ...).
Paths are resolved (~, .., symlinks) before checking, and matching is case-insensitive like APFS.
Restricting further (opt-in). To confine writes or attachments to specific folders, list them (colon-separated) in the server's env, or pass --write-dir / --attach-dir (repeatable) as arguments. Once set, only those folders are allowed for that side, and the denylist still applies inside them. The tool's own cache (~/Library/Caches/apple-mail-mcp, the default rich-draft location) stays writable.
"env": {
"APPLE_MAIL_MCP_WRITE_DIRS": "~/Downloads:~/Documents/mail-exports",
"APPLE_MAIL_MCP_ATTACH_DIRS": "~/Documents:~/Desktop"
}Usage Examples
Show me an overview of my inbox
Search for emails about "project update" in my Gmail
Reply to the email about "Domain name" with "Thanks for the update!"
Move emails with "invoice" in the subject to my Archive folder
Show me email statistics for the last 30 days
Create a rich HTML draft for a weekly update and open it in MailRich HTML Drafts
Use create_rich_email_draft when you need a visually formatted email, newsletter, or leadership update.
It generates an unsent
.emlfile with multipart plain-text + HTML bodiesIt can open the draft directly in Mail for editing
It can optionally ask Mail to save the opened compose window into Drafts
It accepts partial details, so you can start with just an account and subject and fill in the rest later
This is more reliable than injecting raw HTML into AppleScript content, which Mail often stores as literal markup.
Email Management Skill
A companion Claude Code Skill is included that teaches Claude expert email workflows (Inbox Zero, daily triage, folder organization). When installed as a plugin, the skill is loaded automatically. For standalone MCP installs, add it with npx skills add patrickfreyer/apple-mail-mcp or copy it manually:
cp -r plugin/skills/email-management ~/.claude/skills/email-managementRequirements
macOS with Apple Mail configured
Python 3.7+
fastmcp(+ optionalmcp-ui-serverfor dashboard)Claude Desktop or any MCP-compatible client
Mail.app permissions: Automation + Mail Data Access (grant in System Settings > Privacy & Security > Automation)
Troubleshooting
Issue | Fix |
Mail.app not responding | Ensure Mail.app is running; check Automation permissions in System Settings |
Slow searches | Set |
Mailbox not found | Use exact folder names; nested folders use |
Permission errors | Grant access in System Settings > Privacy & Security > Automation |
Rich draft shows raw HTML | Use |
Project Structure
apple-mail-mcp/
├── .claude-plugin/
│ └── marketplace.json # Marketplace manifest (for plugin distribution)
├── plugin/ # Claude Code plugin
│ ├── .claude-plugin/
│ │ └── plugin.json # Plugin manifest
│ ├── skills/ # Email Management Expert skill (also invocable as /email-management)
│ ├── apple_mail_mcp/ # Python MCP server package (24 tools)
│ ├── apple_mail_mcp.py # Entry point
│ ├── start_mcp.sh # Startup wrapper (auto-creates venv)
│ └── requirements.txt
├── apple-mail-mcpb/ # MCPB build files (Claude Desktop)
├── LICENSE
└── README.mdContributing
Fork the repository
Create a feature branch (
git checkout -b feature/my-feature)Commit and push
Open a Pull Request
Releasing
Follow these steps when cutting a new release to keep all version strings in sync:
Bump
__version__inplugin/apple_mail_mcp/__init__.pyto the new version.Update
apple-mail-mcpb/manifest.json("version"field) to match.Update
pyproject.toml(version = ...under[project]) to match.Update both version fields in
server.json("version"and"packages"[0]["version"]) to match.Run
python3 scripts/check_versions.py— it must print OK before you proceed.Commit, tag, and push:
git tag vX.Y.Z && git push origin vX.Y.Z.Create a GitHub release from the tag.
Build and publish to PyPI:
python -m build && twine upload dist/*(requires PyPI credentials).
The test suite also enforces version consistency (
tests/test_version_consistency.py), so any CI run on a branch with mismatched versions will fail fast.
License
MIT -- see LICENSE.
Links
Available Tools
38 toolsarchive_emailsA
Archive emails matching criteria by moving them to an Archive mailbox.
Safety features:
At least one filter (subject_keyword, sender, or older_than_days) is required.
dry_run=True (default) previews what would be archived without moving.
only_read=True (default) skips unread emails.
max_archive caps the number of emails moved in one call.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Optional keyword to filter by subject sender: Optional sender to filter by older_than_days: Optional age filter - only archive emails older than N days only_read: If True (default), only archive emails that have been read from_mailbox: Source mailbox (default "INBOX") archive_mailbox: Destination mailbox (default "Archive") max_archive: Maximum emails to archive per call (default 50) dry_run: If True (default), only preview - do not actually move emails
Returns: Summary of archived (or previewed) emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), sender, dry_run, only_read, +5 more. Returns: result
bulk_move_emailsA
Move multiple emails matching filters to a destination mailbox.
Both from_mailbox (source) and to_mailbox (destination) are required. At least one filter (subject_keyword, sender, or older_than_days) is required.
Args: account: Account name (e.g., "Gmail", "Work") to_mailbox: Destination mailbox. Use "/" for nested mailboxes (e.g., "Projects/ClientX") subject_keyword: Optional keyword to filter emails by subject sender: Optional sender email/name to filter by from_mailbox: Source mailbox (default: "INBOX") older_than_days: Only affect emails older than N days max_emails: Maximum number of emails to move (safety limit, default: 50) dry_run: If True, preview what would be moved without acting (default: False)
Returns: Summary of moved emails with count
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), to_mailbox (required), sender, dry_run, +4 more. Returns: result
compose_emailA
Compose and send a new email from a specific account.
Args: account: Account name to send from (e.g., "Gmail", "Work", "Personal") to: Recipient email address(es), comma-separated for multiple subject: Email subject line body: Email body text (plain-text fallback when body_html is used) cc: Optional CC recipients, comma-separated for multiple bcc: Optional BCC recipients, comma-separated for multiple attachments: Optional file paths to attach, comma-separated for multiple (e.g., "/path/to/file1.png,/path/to/file2.pdf") mode: Delivery mode — "send" (send immediately, default), "draft" (save silently to Drafts), or "open" (open compose window for review before sending) body_html: Optional HTML email body for rich formatting
Returns: Confirmation message with details of the email
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: to (required), body (required), account (required), subject (required), +5 more. Returns: result
create_mailboxA
Create a new mailbox (folder) in the specified account.
Supports nested paths via the parent_mailbox parameter (e.g., parent_mailbox="Projects" + name="2024" creates Projects/2024). You can also pass a full slash-separated path as name (e.g., "Projects/2024/ClientName") and omit parent_mailbox.
Args: account: Account name (e.g., "Gmail", "Work") name: Name for the new mailbox. May contain "/" to create a nested path in one call (each segment is created if needed). parent_mailbox: Optional existing parent folder for nesting.
Returns: Confirmation with the new mailbox path.
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: name (required), account (required), parent_mailbox. Returns: result
delete_emailsA
Soft-delete emails (move to Trash) matching filters, with safety features.
IMPORTANT: dry_run=True by default -- shows what WOULD be deleted without acting. Set dry_run=False to actually move emails to Trash.
At least one filter (subject_keyword, sender, or older_than_days) is required. Emails are moved to Trash, never permanently deleted.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Optional keyword to filter emails by subject sender: Optional sender email/name to filter by older_than_days: Only affect emails older than N days mailbox: Source mailbox to search in (default: "INBOX") max_emails: Maximum number of emails to delete (safety limit, default: 25) dry_run: If True (default), only preview what would be deleted
Returns: List of affected email subjects and count
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), sender, dry_run, mailbox, +3 more. Returns: result
export_emailsA
Export emails to files for backup or analysis.
Args: account: Account name (e.g., "Gmail", "Work") scope: Export scope: "single_email" (requires subject_keyword) or "entire_mailbox" subject_keyword: Keyword to find email (required for single_email) mailbox: Mailbox to export from (default: "INBOX") save_directory: Directory to save exports (default: "~/Desktop") format: Export format: "txt", "html" (default: "txt") max_emails: Maximum number of emails to export for entire_mailbox (default: 1000, safety cap)
Returns: Confirmation message with export location
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: scope (required), account (required), format, mailbox, +3 more. Returns: result
forward_emailA
Forward an email to one or more recipients.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Keyword to search for in email subjects to: Recipient email address(es), comma-separated for multiple message: Optional message to add before forwarded content mailbox: Mailbox to search in (default: "INBOX") cc: Optional CC recipients, comma-separated for multiple bcc: Optional BCC recipients, comma-separated for multiple
Returns: Confirmation message with details of forwarded email
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: to (required), account (required), subject_keyword (required), cc, +3 more. Returns: result
get_awaiting_replyA
Find sent emails that haven't received a reply yet.
Scans the Sent mailbox for outgoing emails and cross-references with the Inbox to see if a reply (matching subject) was received from the same recipient. Useful for follow-up tracking.
Args: account: Account name (e.g., "Gmail", "Work", "Personal") days_back: How many days back to check sent emails (default: 7) exclude_noreply: Skip emails sent to noreply/no-reply addresses (default: True) max_results: Maximum results to return (default: 20)
Returns: List of sent emails still awaiting a reply with subject, recipient, and date sent
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), days_back, max_results, exclude_noreply. Returns: result
get_email_threadA
Get an email conversation thread - all messages with the same or similar subject.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Keyword to identify the thread (e.g., "Re: Project Update") mailbox: Mailbox to search in (default: "INBOX", use "All" for all mailboxes) max_messages: Maximum number of thread messages to return (default: 50)
Returns: Formatted thread view with all related messages sorted by date
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), subject_keyword (required), mailbox, max_messages. Returns: result
get_email_with_contentA
Search for emails by subject keyword and return with full content preview.
Args: account: Account name to search in (e.g., "Gmail", "Work") subject_keyword: Keyword to search for in email subjects max_results: Maximum number of matching emails to return (default: 5) max_content_length: Maximum content length in characters (default: 300, 0 = unlimited) mailbox: Mailbox to search (default: "INBOX", use "All" for all mailboxes)
Returns: Detailed email information including content preview
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), subject_keyword (required), mailbox, max_results, +1 more. Returns: result
get_inbox_overviewA
Get a comprehensive overview of your email inbox status across all accounts.
Returns: Comprehensive overview including: - Unread email counts by account - List of available mailboxes/folders - AI suggestions for actions (move emails, respond to messages, highlight action items, etc.)
This tool is designed to give you a complete picture of your inbox and prompt the assistant to suggest relevant actions based on the current state.
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: no named parameters. Returns: result
get_needs_responseA
Identify unread emails that likely need a response from you.
Filters out newsletters, automated emails, and noreply senders. Prioritises direct emails (To: you) with question marks as likely needing a reply.
Args: account: Account name (e.g., "Gmail", "Work", "Personal") mailbox: Mailbox to scan (default: "INBOX") days_back: How many days back to look (default: 7) max_results: Maximum results to return (default: 20)
Returns: Ranked list of emails likely needing a response, with priority hints
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), mailbox, days_back, max_results. Returns: result
get_newslettersB
Find newsletter and digest emails by detecting common patterns. Automatically identifies emails from newsletter services and digest senders.
Args: account: Account to search. If None, searches all accounts. days_back: Only search last N days (default: 7) max_results: Maximum newsletters to return (default: 25) include_content: Include content preview (default: True) max_content_length: Max preview length (default: 500)
Returns: List of detected newsletter emails sorted by date
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account, days_back, max_results, include_content, +1 more. Returns: result
get_recent_emailsA
Get the most recent emails from a specific account.
Args: account: Account name (e.g., "Gmail", "Work") count: Number of recent emails to retrieve (default: 10) include_content: Whether to include content preview (slower, default: False) output_format: "text" (default, human-readable) or "json" (structured list of email dicts)
Returns: Formatted list of recent emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), count, output_format, include_content. Returns: result
get_recent_from_senderA
Get recent emails from a specific sender with simple, human-friendly time filters.
Args: sender: Sender name or email to search for (partial match) account: Optional account. If None, searches all accounts. time_range: Human-friendly time filter: - "today" = last 24 hours - "yesterday" = yesterday only - "week" = last 7 days (default) - "month" = last 30 days - "all" = no time filter max_results: Maximum emails to return (default: 15) include_content: Include content preview (default: True) max_content_length: Max preview length (default: 400) mailbox: Mailbox to search (default: "INBOX", use "All" for all mailboxes)
Returns: Recent emails from the specified sender within the time range
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: sender (required), account, mailbox, time_range, +3 more. Returns: result
get_statisticsA
Get comprehensive email statistics and analytics.
Args: account: Account name (e.g., "Gmail", "Work") scope: Analysis scope: "account_overview", "sender_stats", "mailbox_breakdown" sender: Specific sender for "sender_stats" scope mailbox: Specific mailbox for "mailbox_breakdown" scope days_back: Number of days to analyze (default: 30, 0 = all time)
Returns: Formatted statistics report with metrics and insights
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), scope, sender, mailbox, +1 more. Returns: result
get_top_sendersA
Analyse a mailbox to find the most frequent senders.
Useful for identifying key contacts, high-volume senders to filter, or newsletter sources to unsubscribe from.
Args: account: Account name (e.g., "Gmail", "Work", "Personal") mailbox: Mailbox to analyse (default: "INBOX") days_back: How many days back to look (default: 30, 0 = all time) top_n: Number of top senders to return (default: 10) group_by_domain: Group results by domain instead of individual sender (default: False)
Returns: Ranked list of senders (or domains) with email counts
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), top_n, mailbox, days_back, +1 more. Returns: result
get_unread_countB
Get the count of unread emails for each account.
Returns: Dictionary mapping account names to unread email counts
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: no named parameters. Returns: object
imap_bulk_moveA
Move emails between IMAP folders directly (fast, for Proton Bridge).
Much faster than AppleScript for large mailboxes. Optionally filter by sender. Writes progress to /tmp/apple-mail-mcp-sort.log (tail -f to monitor).
Requires config: ~/.config/apple-mail-mcp/imap.json
Args: from_mailbox: Source mailbox (e.g., "INBOX", "Rechnungen", "IT/Netflix") to_mailbox: Destination mailbox (e.g., "Finanzen/Rechnungen") sender: Optional sender pattern to filter by (case-insensitive substring) max_moves: Maximum emails to move (safety limit, default: 100) dry_run: If True, only count matches without moving (default: True)
Returns: Summary of moved emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: to_mailbox (required), from_mailbox (required), sender, dry_run, +1 more. Returns: result
inbox_dashboardA
Get an interactive dashboard view of your email inbox.
Returns an interactive UI dashboard resource that displays:
Unread email counts by account (visual cards with badges)
Recent emails across all accounts (filterable list)
Quick action buttons for common operations (Mark Read, Archive, Delete)
Search functionality to filter emails
This tool returns a UIResource that can be rendered by compatible MCP clients (like Claude Desktop with MCP Apps support) to provide an interactive dashboard experience.
Note: Requires mcp-ui-server package and a compatible MCP client.
Returns: UIResource with uri "ui://apple-mail/inbox-dashboard" containing an interactive HTML dashboard, or error message if UI is unavailable.
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: no named parameters.
list_accountsA
List all available Mail accounts.
Returns: List of account names
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: no named parameters. Returns: result
list_email_attachmentsB
List attachments for emails matching a subject keyword.
Args: account: Account name (e.g., "Gmail", "Work", "Personal") subject_keyword: Keyword to search for in email subjects max_results: Maximum number of matching emails to check (default: 1)
Returns: List of attachments with their names and sizes
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), subject_keyword (required), max_results. Returns: result
list_inbox_emailsB
List all emails from inbox across all accounts or a specific account.
Args: account: Optional account name to filter (e.g., "Gmail", "Work"). If None, shows all accounts. max_emails: Maximum number of emails to return per account (0 = all) include_read: Whether to include read emails (default: True) output_format: "text" (default, human-readable) or "json" (structured list of email dicts)
Returns: Formatted list of emails with subject, sender, date, and read status
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account, max_emails, include_read, output_format. Returns: result
list_mailboxesA
List all mailboxes (folders) for a specific account or all accounts.
Args: account: Optional account name to filter (e.g., "Gmail", "Work"). If None, shows all accounts. include_counts: Whether to include message counts for each mailbox (default: True)
Returns: Formatted list of mailboxes with optional message counts. For nested mailboxes, shows both indented format and path format (e.g., "Projects/Amplify Impact")
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account, include_counts. Returns: result
manage_draftsA
Manage draft emails - list, create, send, open, or delete drafts.
Args: account: Account name (e.g., "Gmail", "Work") action: Action to perform: "list", "create", "send", "open", "delete". Use "open" to open a draft in a visible compose window for review before sending. subject: Email subject (required for create) to: Recipient email(s) for create (comma-separated) body: Email body (required for create) cc: Optional CC recipients for create bcc: Optional BCC recipients for create draft_subject: Subject keyword to find draft (required for send/open/delete)
Returns: Formatted output based on action
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: action (required), account (required), cc, to, +4 more. Returns: result
manage_trashA
Manage trash operations - delete emails or empty trash.
Args: account: Account name (e.g., "Gmail", "Work") action: Action to perform: "move_to_trash", "delete_permanent", "empty_trash" subject_keyword: Optional keyword to filter emails (not used for empty_trash) sender: Optional sender to filter emails (not used for empty_trash) mailbox: Source mailbox (default: "INBOX", not used for empty_trash or delete_permanent) max_deletes: Maximum number of emails to delete (safety limit, default: 5) confirm_empty: Must be True to execute "empty_trash" action (safety confirmation) apply_to_all: Must be True to allow operations without subject_keyword or sender filter
Returns: Confirmation message with details of deleted emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: action (required), account (required), sender, mailbox, +4 more. Returns: result
mark_emailsA
Batch mark emails as read/unread and/or flagged/unflagged.
At least one filter (subject_keyword, sender, or older_than_days) is required.
Args: account: Account name (e.g., "Gmail", "Work") action: Action to perform: "read", "unread", "flagged", "unflagged" subject_keyword: Optional keyword to filter emails by subject sender: Optional sender email/name to filter by mailbox: Mailbox to search in (default: "INBOX") older_than_days: Only affect emails older than N days max_emails: Maximum number of emails to update (safety limit, default: 50)
Returns: Summary of affected emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: action (required), account (required), sender, mailbox, +3 more. Returns: result
move_emailA
Move email(s) matching a subject keyword from one mailbox to another.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Keyword to search for in email subjects to_mailbox: Destination mailbox name. For nested mailboxes, use "/" separator (e.g., "Projects/Amplify Impact") from_mailbox: Source mailbox name (default: "INBOX") max_moves: Maximum number of emails to move (default: 1, safety limit) message_ids: Exact Apple Mail message ids to move; when provided, subject filtering is ignored
Returns: Confirmation message with details of moved emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), to_mailbox (required), subject_keyword (required), max_moves, +2 more. Returns: result
reply_to_emailA
Reply to an email matching a subject keyword.
Args: account: Account name (e.g., "Gmail", "Work") subject_keyword: Keyword to search for in email subjects reply_body: The body text of the reply reply_to_all: If True, reply to all recipients; if False, reply only to sender (default: False) cc: Optional CC recipients, comma-separated for multiple bcc: Optional BCC recipients, comma-separated for multiple send: If True (default), send immediately; if False, save as draft. Ignored if mode is set. mode: Delivery mode — "send" (send immediately), "draft" (save silently), or "open" (open compose window for review). Overrides send parameter when set. attachments: Optional file paths to attach, comma-separated for multiple (e.g., "/path/to/file1.png,/path/to/file2.pdf")
Returns: Confirmation message with details of the reply sent, saved draft, or opened draft
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), reply_body (required), subject_keyword (required), cc, +5 more. Returns: result
save_email_attachmentA
Save a specific attachment from an email to disk.
Args: account: Account name (e.g., "Gmail", "Work", "Personal") subject_keyword: Keyword to search for in email subjects attachment_name: Name of the attachment to save save_path: Full path where to save the attachment
Returns: Confirmation message with save location
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), save_path (required), attachment_name (required), subject_keyword (required). Returns: result
search_all_accountsA
Search across ALL email accounts at once.
Returns consolidated results sorted by date (newest first). Only searches INBOX mailboxes (skips Trash, Junk, Drafts, Sent).
Args: subject_keyword: Optional keyword to search in subject sender: Optional sender email or name to filter by days_back: Number of days to look back (default: 7, 0 = all time) max_results: Maximum total results across all accounts (default: 30) include_content: Whether to include email content preview (default: True) max_content_length: Maximum content length in characters (default: 400)
Returns: Formatted list of matching emails with account name for each
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: sender, days_back, max_results, include_content, +2 more. Returns: result
search_by_senderA
Find all emails from a specific sender across one or all accounts. Perfect for tracking newsletters, contacts, or communications from specific people/organizations.
Args: sender: Sender name or email to search for (partial match, e.g., "alphasignal" or "john@") account: Optional account name. If None, searches all accounts. days_back: Only search emails from the last N days (default: 30, 0 = all time) max_results: Maximum number of emails to return (default: 20) include_content: Whether to include email content preview (default: True) max_content_length: Maximum length of content preview (default: 500) mailbox: Mailbox to search (default: "INBOX", use "All" for all mailboxes)
Returns: Formatted list of emails from the sender, sorted by date (newest first)
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: sender (required), account, mailbox, days_back, +3 more. Returns: result
search_email_contentA
Search email body content (and optionally subject). This is slower than subject-only search but finds more relevant results.
Args: account: Account name to search in search_text: Text to search for in email content mailbox: Mailbox to search (default: "INBOX") search_subject: Also search in subject line (default: True) search_body: Search in email body (default: True) max_results: Maximum results to return (default: 10, keep low as this is slow) max_content_length: Max content preview length (default: 600)
Returns: Emails where the search text appears in body and/or subject
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), search_text (required), mailbox, max_results, +3 more. Returns: result
search_emailsA
Unified search tool - search emails with advanced filtering across any mailbox.
Args: account: Account name to search in (e.g., "Gmail", "Work") mailbox: Mailbox to search (default: "INBOX", use "All" for all mailboxes, or specific folder name) subject_keyword: Optional keyword to search in subject sender: Optional sender email or name to filter by has_attachments: Optional filter for emails with attachments (True/False/None) read_status: Filter by read status: "all", "read", "unread" (default: "all") date_from: Optional start date filter (format: "YYYY-MM-DD") date_to: Optional end date filter (format: "YYYY-MM-DD") include_content: Whether to include email content preview (slower) max_results: Maximum number of results to return (default: 20) output_format: "text" (default, human-readable) or "json" (structured list of email dicts) flag_color: Optional flag color filter: red, orange, yellow, green, blue, purple, gray
Returns: Formatted list of matching emails with all requested details
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account (required), sender, date_to, mailbox, +8 more. Returns: result
search_emails_advancedA
Powerful unified search across accounts and mailboxes with flexible filters.
Combines the capabilities of search_emails, search_by_sender, search_email_content, and search_all_accounts into one tool. When account is None, all accounts are searched.
Uses IMAP when available (much faster, no Mail.app freezes). Falls back to AppleScript for accounts without IMAP configuration.
Args: account: Account to search (None = all accounts) mailbox: Mailbox name (default "INBOX", "All" for all mailboxes) subject_contains: Filter by subject keyword (case-insensitive) body_contains: Filter by body text (slower, case-insensitive) sender_contains: Filter by sender name/email (case-insensitive) to_contains: Filter by To recipient address (case-insensitive, IMAP-accelerated) cc_contains: Filter by CC recipient address (case-insensitive, IMAP-accelerated) date_from: Start date "YYYY-MM-DD" (inclusive) date_to: End date "YYYY-MM-DD" (inclusive) is_read: Filter by read status (True/False/None for any) has_attachments: Filter by attachment presence (True/False/None) is_flagged: Filter by flagged status (True/False/None) max_results: Maximum results (default 50) offset: Skip first N results for pagination (default 0) output_format: "text" (human-readable) or "json" (structured)
Returns: Matching emails across the specified scope
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: offset, account, date_to, is_read, +11 more. Returns: result
sort_inboxA
Sort inbox emails into folders by sender using IMAP (fast, for Proton Bridge).
Reads sorting rules from ~/.config/apple-mail-mcp/sort_rules.json. Each rule maps a sender pattern to a destination folder.
Writes real-time progress to /tmp/apple-mail-mcp-sort.log (tail -f to monitor).
Supports batch processing: set batch_size to move N emails per call. Call repeatedly until inbox is clean — already-moved emails are skipped.
Requires config: ~/.config/apple-mail-mcp/imap.json
Args: dry_run: If True, only show what would happen without moving (default: True) max_emails: Maximum emails to scan (0 = all) batch_size: Max emails to move per call (0 = all matched). Use 100-200 to avoid timeouts. rules_path: Optional custom path to sort_rules.json create_folders: Auto-create destination folders that don't exist (default: True)
Returns: Summary of emails scanned, matched, and moved
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: dry_run, batch_size, max_emails, rules_path, +1 more. Returns: result
synchronize_accountA
Ask Apple Mail to synchronize one account or all accounts.
Args: account: Optional account name. When omitted, all accounts are synchronized.
Returns: Summary of synchronization requests. Mail may continue syncing after this tool returns.
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: account. Returns: result
update_email_statusA
Update email status - mark as read/unread or flag/unflag emails.
Args: account: Account name (e.g., "Gmail", "Work") action: Action to perform: "mark_read", "mark_unread", "flag", "unflag" subject_keyword: Optional keyword to filter emails by subject sender: Optional sender to filter emails by mailbox: Mailbox to search in (default: "INBOX") max_updates: Maximum number of emails to update (safety limit, default: 10) apply_to_all: Must be True to allow updates without subject_keyword or sender filter message_ids: Exact Apple Mail message ids to update; when provided, filters are ignored flag_color: Optional flag color for action="flag": red, orange, yellow, green, blue, purple, gray
Returns: Confirmation message with details of updated emails
User Preferences: {"workflow": "default", "notifications": "enabled"}
Inputs: action (required), account (required), sender, mailbox, +5 more. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 38 tools
Multiple tools have overlapping functionality (e.g., search_emails, search_by_sender, search_email_content, search_all_accounts, search_emails_advanced; mark_emails and update_email_status; move_email, bulk_move_emails, imap_bulk_move). Agents may struggle to select the right tool despite detailed descriptions.
Tool names generally follow a verb_noun pattern in snake_case, but verbs are inconsistent: 'get', 'list', 'search', 'find' are used interchangeably for similar retrieval tasks. For example, 'get_recent_emails' vs 'get_recent_from_sender' vs 'search_by_sender'.
38 tools is excessive for an email MCP server. Many tools are highly specialized (e.g., get_newsletters, get_top_senders, get_awaiting_reply), which inflates the count and could overwhelm agents. A more streamlined set of 15-20 tools would be more appropriate.
Core email operations are well-covered: reading, searching, composing, replying, forwarding, moving, archiving, deleting, trash management, drafts, mailboxes, statistics, and exports. Minor gaps exist (e.g., contact management, account setup), but the surface is largely complete for typical email workflows.
Maintenance
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Your IMAP mailbox as an MCP server: read, search and (if you allow it) organize mail. Open source.
Email inboxes for AI agents: send, receive, reply, search, and manage threaded email over MCP.
Email for AI agents: read, search and send from your Gmail, Outlook, Yahoo, iCloud or IMAP inbox.
Related MCP Servers
- AlicenseAqualityAmaintenanceThis 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.524,105 npm107MIT
- AlicenseNot gradedqualityFmaintenanceAn MCP server that receives emails on your domain and allows AI assistants to search, read, and manage them via natural language queries.1,191 npmMIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI assistants comprehensive access to Apple Mail accounts, enabling email discovery, reading, flag management, and server-side message retrieval.MIT
- AlicenseAqualityBmaintenanceAn MCP server that provides programmatic access to Apple Mail, enabling AI assistants like Claude to read, send, search, and manage emails on macOS.25MIT