Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

apple-mail-mcp

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

apple-mail-mcp

MCP server for Apple Mail - read, search, send, and manage emails via Claude

latest
Source
npmnpm
Version
1.5.5
Version published
Weekly downloads
219
-70.49%
Maintainers
1
Weekly downloads
 
Created
Source

Apple Mail MCP Server

A Model Context Protocol (MCP) server that enables AI assistants like Claude to read, send, search, and manage emails in Apple Mail on macOS.

npm version CI License: MIT

Note: This is the npm/Node.js package — install with npx or npm. There is an unrelated Python project of the same name on PyPI (imdinu/apple-mail-mcp) installed via pipx/uvx. If you're using uvx and seeing a cyclopts dependency error, you're looking for that project, not this one.

What is This?

This server acts as a bridge between AI assistants and Apple Mail. Once configured, you can ask Claude (or any MCP-compatible AI) to:

  • "Check my inbox for unread messages"
  • "Find emails from john@example.com"
  • "Send an email to the team about the meeting"
  • "Create a draft email for me to review"
  • "Reply to that message"
  • "Forward this to my colleague"
  • "Move old newsletters to the Archive folder"

The AI assistant communicates with this server, which then uses AppleScript to interact with the Mail app on your Mac. All data stays local on your machine.

Quick Start

Using Claude Code (Easiest)

If you're using Claude Code (in Terminal or VS Code), just ask Claude to install it:

Install the sweetrb/apple-mail-mcp MCP server so you can help me manage my Apple Mail

Claude will handle the installation and configuration automatically.

Using the Plugin Marketplace

Install as a Claude Code plugin for automatic configuration and enhanced AI behavior:

/plugin marketplace add sweetrb/apple-mail-mcp
/plugin install apple-mail

This method also installs a skill that teaches Claude when and how to use Apple Mail effectively.

Manual Installation

1. Install the server:

npm install -g github:sweetrb/apple-mail-mcp

2. Add to Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "apple-mail": {
      "command": "npx",
      "args": ["apple-mail-mcp"]
    }
  }
}

3. Restart Claude Desktop and start using natural language:

"Show me my unread emails"

On first use, macOS will ask for permission to automate Mail.app. Click "OK" to allow.

Requirements

  • macOS - Apple Mail and AppleScript are macOS-only
  • Node.js 20+ - Required for the MCP server
  • Apple Mail - Must have at least one account configured (iCloud, Gmail, Exchange, etc.)

Features

Messages

FeatureDescription
List MessagesList messages with pagination, sender filter, date display
Search MessagesSearch by sender, subject, content, date range, read/flagged status — across all accounts
Read MessagesGet full email content (plain text or HTML)
Send EmailCompose and send new emails (with optional file attachments)
Send Serial EmailMail merge — send personalized emails to a list of recipients with {{placeholder}} support
Create DraftSave emails to Drafts folder (with optional file attachments)
ReplyReply to messages (with reply-all support)
ForwardForward messages to new recipients
Mark Read/UnreadChange read status (single or batch)
Flag/UnflagFlag or unflag messages (single or batch)
Delete MessagesMove messages to trash (single or batch)
Move MessagesOrganize into mailboxes (single or batch)
List AttachmentsView attachment metadata (name, type, size)
Save AttachmentSave attachments to disk

Mailbox & Account Management

FeatureDescription
List MailboxesShow all folders with message/unread counts
Create/Delete/Rename MailboxFull mailbox lifecycle management
List AccountsShow configured accounts
Unread CountGet unread counts per mailbox

Rules, Contacts & Templates

FeatureDescription
List RulesView all mail rules and their enabled status
Enable/Disable RulesToggle mail rules on or off
Search ContactsLook up contacts from Contacts.app by name
Email TemplatesSave, list, use, and delete reusable email templates

Diagnostics

FeatureDescription
Health CheckVerify Mail.app connectivity
StatisticsMessage and unread counts per account, recently received stats
Sync StatusCheck if Mail.app is actively syncing

Tool Reference

This section documents all available tools. AI agents should use these tool names and parameters exactly as specified.

Message Operations

search-messages

Search for messages matching criteria. Searches all accounts by default.

ParameterTypeRequiredDescription
querystringNoText to search in subject/sender
fromstringNoFilter by sender email address
subjectstringNoFilter by subject line
mailboxstringNoMailbox to search in (omit to search all mailboxes)
accountstringNoAccount to search in (omit to search all accounts)
isReadbooleanNoFilter by read status
isFlaggedbooleanNoFilter by flagged status
dateFromstringNoStart date filter (e.g., "January 1, 2026")
dateTostringNoEnd date filter (e.g., "March 1, 2026")
limitnumberNoMax results (default: 50)

get-message

Get the full content of a message.

ParameterTypeRequiredDescription
idstringYesMessage ID
preferHtmlbooleanNoReturn HTML source instead of plain text

Returns: Subject line and message body (plain text by default, HTML if preferHtml is true and HTML content is available).

list-messages

List messages in a mailbox.

ParameterTypeRequiredDescription
mailboxstringNoMailbox name (omit to list from all mailboxes)
accountstringNoAccount name
limitnumberNoMax messages (default: 50)
offsetnumberNoNumber of messages to skip (for pagination)
fromstringNoFilter by sender email address or name
unreadOnlybooleanNoOnly show unread messages

Returns: List of messages with ID, date, subject, and sender.

send-email

Send a new email immediately.

ParameterTypeRequiredDescription
tostring[]YesRecipient addresses
subjectstringYesEmail subject
bodystringYesEmail body (plain text)
ccstring[]NoCC recipients
bccstring[]NoBCC recipients
accountstringNoSend from specific account
attachmentsstring[]NoAbsolute file paths to attach, max 20 files (e.g., ["/Users/me/report.pdf"])

Example:

{
  "to": ["colleague@company.com"],
  "subject": "Meeting Tomorrow",
  "body": "Hi, just confirming our meeting at 2pm tomorrow.",
  "account": "Work",
  "attachments": ["/Users/me/Documents/agenda.pdf"]
}

send-serial-email

Send individual personalized emails to a list of recipients (mail merge). Each recipient receives their own email — recipients don't see each other. Supports {{placeholder}} tokens in both subject and body.

ParameterTypeRequiredDescription
recipientsobject[]YesList of recipients, max 100 (see below)
subjectstringYesEmail subject — use {{Key}} for placeholders
bodystringYesEmail body — use {{Key}} for placeholders
accountstringNoSend from specific account
delayMsnumberNoDelay between sends in ms (default: 500, max 10000)

Each recipient object:

FieldTypeRequiredDescription
emailstringYesRecipient email address
variablesobjectYesKey-value pairs for placeholder replacement

Example:

{
  "recipients": [
    { "email": "alice@example.com", "variables": { "Name": "Alice", "Company": "Acme" } },
    { "email": "bob@example.com", "variables": { "Name": "Bob", "Company": "Globex" } }
  ],
  "subject": "Hello {{Name}}!",
  "body": "Dear {{Name}},\n\nGreat to connect about {{Company}}.\n\nBest regards"
}

Returns: Per-recipient success/failure results with a summary count.

create-draft

Save an email to Drafts without sending.

ParameterTypeRequiredDescription
tostring[]YesRecipient addresses
subjectstringYesEmail subject
bodystringYesEmail body (plain text)
ccstring[]NoCC recipients
bccstring[]NoBCC recipients
accountstringNoAccount for draft
attachmentsstring[]NoAbsolute file paths to attach, max 20 files

Returns: Confirmation that draft was created.

reply-to-message

Reply to an existing message.

ParameterTypeRequiredDescription
idstringYesMessage ID to reply to
bodystringYesReply body
replyAllbooleanNoReply to all recipients (default: false)
sendbooleanNoSend immediately (default: true, false = save as draft)

Example - Reply to sender only:

{
  "id": "12345",
  "body": "Thanks for the update!"
}

Example - Reply all, save as draft:

{
  "id": "12345",
  "body": "I'll review this and get back to everyone.",
  "replyAll": true,
  "send": false
}

forward-message

Forward a message to new recipients.

ParameterTypeRequiredDescription
idstringYesMessage ID to forward
tostring[]YesRecipients to forward to
bodystringNoMessage to prepend
sendbooleanNoSend immediately (default: true, false = save as draft)

mark-as-read / mark-as-unread

Change read status of a message.

ParameterTypeRequiredDescription
idstringYesMessage ID

flag-message / unflag-message

Flag or unflag a message.

ParameterTypeRequiredDescription
idstringYesMessage ID

delete-message

Delete a message (move to trash).

ParameterTypeRequiredDescription
idstringYesMessage ID

move-message

Move a message to a different mailbox.

ParameterTypeRequiredDescription
idstringYesMessage ID
mailboxstringYesDestination mailbox
accountstringNoAccount containing mailbox

list-attachments

List attachments on a message.

ParameterTypeRequiredDescription
idstringYesMessage ID

Returns: List of attachments with name, MIME type, and size.

save-attachment

Save a message attachment to disk.

ParameterTypeRequiredDescription
idstringYesMessage ID
attachmentNamestringYesFilename of the attachment
savePathstringYesDirectory to save to

Batch Operations

All batch operations accept an array of message IDs (max 100 per batch) and return per-item success/failure results.

batch-delete-messages

ParameterTypeRequiredDescription
idsstring[]YesMessage IDs to delete (max 100)

batch-move-messages

ParameterTypeRequiredDescription
idsstring[]YesMessage IDs to move (max 100)
mailboxstringYesDestination mailbox
accountstringNoAccount containing mailbox

batch-mark-as-read / batch-mark-as-unread

ParameterTypeRequiredDescription
idsstring[]YesMessage IDs (max 100)

batch-flag-messages / batch-unflag-messages

ParameterTypeRequiredDescription
idsstring[]YesMessage IDs (max 100)

Mailbox Operations

list-mailboxes

List all mailboxes for an account.

ParameterTypeRequiredDescription
accountstringNoAccount to list from

Returns: List of mailbox names with message and unread counts.

get-unread-count

Get unread message count.

ParameterTypeRequiredDescription
mailboxstringNoMailbox to check (omit for total)
accountstringNoAccount to check

create-mailbox

Create a new mailbox.

ParameterTypeRequiredDescription
namestringYesMailbox name
accountstringNoAccount to create in

delete-mailbox

Delete a mailbox.

ParameterTypeRequiredDescription
namestringYesMailbox name
accountstringNoAccount containing mailbox

rename-mailbox

Rename a mailbox (creates new, moves messages, deletes old).

ParameterTypeRequiredDescription
oldNamestringYesCurrent mailbox name
newNamestringYesNew mailbox name
accountstringNoAccount containing mailbox

Account Operations

list-accounts

List all configured Mail accounts.

Parameters: None

Returns: List of account names and email addresses.

Rules

list-rules

List all mail rules.

Parameters: None

Returns: List of rule names and enabled status.

enable-rule / disable-rule

Enable or disable a mail rule.

ParameterTypeRequiredDescription
namestringYesRule name

Contacts

search-contacts

Search contacts in Contacts.app.

ParameterTypeRequiredDescription
querystringYesName to search for
limitnumberNoMax results (default: 10)

Returns: List of contacts with name, email addresses, and phone numbers.

Templates

Email templates are stored in memory for the duration of the server session.

save-template

Save or update an email template.

ParameterTypeRequiredDescription
namestringYesTemplate name
subjectstringYesDefault subject line
bodystringYesTemplate body
tostring[]NoDefault recipients
ccstring[]NoDefault CC recipients
idstringNoTemplate ID (for updating)

list-templates

List all saved templates.

Parameters: None

get-template

Get a template by ID.

ParameterTypeRequiredDescription
idstringYesTemplate ID

delete-template

Delete a template.

ParameterTypeRequiredDescription
idstringYesTemplate ID

use-template

Create a draft from a template, with optional overrides.

ParameterTypeRequiredDescription
idstringYesTemplate ID
tostring[]NoOverride recipients
ccstring[]NoOverride CC
subjectstringNoOverride subject
bodystringNoOverride body

Diagnostics

health-check

Verify Mail.app connectivity and permissions.

Parameters: None

Returns: Status of all health checks (app running, permissions, account access).

get-mail-stats

Get mail statistics.

Parameters: None

Returns: Total and per-account message/unread counts, plus recently received stats (24h, 7d, 30d).

get-sync-status

Check Mail.app sync activity.

Parameters: None

Returns: Whether sync is detected, pending uploads, recent activity, and seconds since last change.

Usage Patterns

Basic Workflow

User: "Check my inbox for new emails"
AI: [calls list-messages]
    "You have 12 messages. Here are the most recent..."

User: "Show me emails from Sarah"
AI: [calls search-messages with query="Sarah"]
    "Found 3 emails from Sarah across all mailboxes..."

User: "Read the first one"
AI: [calls get-message with id="..."]
    "Subject: Project Update..."

Working with Accounts

By default, operations use Mail.app's configured default send account. Search operations check all accounts when no account is specified. To work with specific accounts:

User: "What email accounts do I have?"
AI: [calls list-accounts]
    "You have 3 accounts: iCloud, Gmail, Work Exchange"

User: "Show unread emails in my Work account"
AI: [calls list-messages with account="Work Exchange", mailbox="INBOX"]
    "Your Work account has 5 unread messages..."

Sending Emails Safely

User: "Draft an email to the team about the deadline"
AI: [calls create-draft with to=["team@..."], subject="...", body="..."]
    "I've created a draft. Please review it in Mail.app before sending."

User: "Send it"
AI: [User opens Mail.app and sends manually, or AI calls send-email]

Sending Personalized Emails (Mail Merge)

User: "Send a personalized email to Alice (alice@acme.com), Bob (bob@globex.com),
       and Carol (carol@initech.com). Subject: 'Project Update for {{Company}}',
       Body: 'Hi {{Name}}, here is the latest update for {{Company}}.'"
AI: [calls send-serial-email with recipients, subject template, and body template]
    "Successfully sent 3 email(s):
      - alice@acme.com: sent
      - bob@globex.com: sent
      - carol@initech.com: sent"

Organizing Messages

User: "Move all newsletters to Archive"
AI: [calls search-messages to find newsletters]
AI: [calls move-message for each, with mailbox="Archive"]
    "Moved 8 newsletters to Archive"

Installation Options

npm install -g github:sweetrb/apple-mail-mcp

From Source

git clone https://github.com/sweetrb/apple-mail-mcp.git
cd apple-mail-mcp
npm install
npm run build

If installed from source, use this configuration:

{
  "mcpServers": {
    "apple-mail": {
      "command": "node",
      "args": ["/path/to/apple-mail-mcp/build/index.js"]
    }
  }
}

Running from a clone in Claude Code (project-scope .mcp.json)

This repo ships a .mcp.json at its root so that, when you run claude from inside a clone, the server is registered automatically as a project-scope server — no manual config needed. After npm run build, just launch Claude Code from the repo directory and approve the server when prompted.

The entrypoint is written as:

"args": ["${CLAUDE_PROJECT_DIR:-.}/build/index.js"]

CLAUDE_PROJECT_DIR is the variable Claude Code injects into a project/user-scoped server's environment, and it resolves to the repo root. You must launch claude from inside the repo for this to work — the bare . fallback is only a last resort and is not reliable, because it resolves against the launching process's working directory, not the repo.

Why not ${CLAUDE_PLUGIN_ROOT}? CLAUDE_PLUGIN_ROOT is set only for marketplace plugin installs, never for a project-scope clone, so it can't drive the clone workflow. Conversely, a plugin install can't use CLAUDE_PROJECT_DIR (in a plugin, that points at the user's project, not the plugin's own directory). Claude Code does not support nested defaults like ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}, so a single entrypoint string cannot serve both contexts. The two distribution paths are therefore decoupled: the plugin carries its own MCP config in .claude-plugin/plugin.json (using ${CLAUDE_PLUGIN_ROOT}), while the root .mcp.json is dedicated to the clone workflow (using ${CLAUDE_PROJECT_DIR:-.}). Because plugin.json declares its own mcpServers, the plugin does not also auto-load the root .mcp.json, so there is no double-registration.

Heads-up on scope precedence: project-scope (.mcp.json) outranks user-scope. If you also have an apple-mail entry registered at user scope (e.g. an absolute path in ~/.claude.json), the project-scope entry wins and the user-scope one is ignored entirely. Pick one — for local development on this repo, the project-scope .mcp.json is the intended source. To pin a specific local build instead, register it at local scope (claude mcp add apple-mail -s local -- node /abs/path/build/index.js), which outranks project scope.

Security and Privacy

  • Local only - All operations happen locally via AppleScript. No data is sent to external servers.
  • Permission required - macOS will prompt for automation permission on first use.
  • No credential storage - The server doesn't store any passwords or authentication tokens.
  • Email safety - Use create-draft to review emails before sending.

Known Limitations

LimitationReason
macOS onlyApple Mail and AppleScript are macOS-specific
No sending HTML emailEmails are sent as plain text; reading HTML content is supported
Attachments require absolute pathsFile attachments must use full absolute paths (e.g., /Users/me/file.pdf)
No smart mailboxesCannot access Smart Mailboxes via AppleScript
In-memory templatesEmail templates are not persisted across server restarts
Numeric-only message IDsMessage IDs must contain only digits (validated by schema)
Batch size capBatch operations are limited to 100 messages per request
Date filter formatDate filters must be valid parseable dates (e.g., "January 1, 2026" or "2026-03-15"); bare numbers or non-date strings are rejected
Attachment save path restrictionssave-attachment only allows saving to home directory, /tmp, /private/tmp, and /Volumes; path traversal is blocked
Attachment count limitsend-email and create-draft accept a maximum of 20 file attachments

Reply / Forward from Background Processes (Fixed in v1.4.0)

Prior to v1.4.0, reply-to-message and forward-message would send messages with empty body text when the MCP server ran as a background process (e.g., spawned via execSync from Node.js, which is how Claude Code invokes it).

Root cause: The AppleScript reply msg with opening window command creates a GUI compose window asynchronously. When set content runs immediately after, the window may not be ready, and the content assignment is silently ignored. Delays (delay 1, delay 2) were unreliable — the compose window's readiness depends on system load, Mail.app state, and whether the process has GUI access.

Fix: Replaced with opening window with without opening window for both reply and forward commands. With this approach, set content works immediately and reliably from background processes. In-Reply-To and References headers are still set correctly by Mail.app, and no GUI compose window is opened.

See #7 for full details and the list of approaches that were tested.

Backslash Escaping (Important for AI Agents)

When sending content containing backslashes (\) to this MCP server, you must escape them as \\ in the JSON parameters.

Why: The MCP protocol uses JSON for parameter passing. In JSON, a single backslash is an escape character. To include a literal backslash in content, it must be escaped as \\.

Example - Email with file path:

{
  "to": ["colleague@company.com"],
  "subject": "File Location",
  "body": "The file is at C:\\\\Users\\\\Documents\\\\report.pdf"
}

The \\\\ in JSON becomes \\ in the actual string, which represents a single \ in the email.

Common patterns requiring escaping:

  • Windows paths: C:\Users\C:\\\\Users\\\\ in JSON
  • Shell escaped spaces: Mobile\ DocumentsMobile\\\\ Documents in JSON
  • Regex patterns: \d+\\\\d+ in JSON

If you see errors when sending emails with backslashes, double-check that backslashes are properly escaped in the JSON payload.

Troubleshooting

"Mail.app not responding"

  • Ensure Mail.app is not frozen
  • Try opening Mail.app manually
  • Restart the MCP server

"Permission denied"

  • macOS needs automation permission
  • Go to System Preferences > Privacy & Security > Automation
  • Ensure your terminal/Claude has permission to control Mail

"Message not found"

  • Message may have been deleted or moved
  • Message IDs change if the message is moved between mailboxes
  • Use search-messages to find the current message ID

"Account not found"

  • Account names must match exactly (case-sensitive)
  • Use list-accounts to see exact account names

"Failed to send email"

  • Check your network connection
  • Verify Mail.app can send emails manually
  • Check if the account is configured correctly in Mail.app

apple-mail server fails to connect when run from a clone

  • The root .mcp.json resolves its entrypoint via ${CLAUDE_PROJECT_DIR:-.}/build/index.js. Launch claude from inside the repo directoryCLAUDE_PROJECT_DIR only resolves to the repo root in that case; the bare . fallback uses the launching shell's working directory and will point at the wrong place otherwise.
  • Run npm run build first — the server is build/index.js, which doesn't exist until you build.
  • Run claude mcp list to check status. If you see a conflicting scopes warning for apple-mail, you have it registered at more than one scope; project-scope wins. See Running from a clone for how scope precedence resolves.
  • If claude mcp get apple-mail shows ⏸ Pending approval, approve the project-scope server (Claude Code prompts on startup, or run it again after approving).

Development

npm install            # Install dependencies
npm run build          # Compile TypeScript
npm test               # Run unit tests
npm run test:integration  # Run integration tests (requires Mail.app)
npm run test:all       # Run all tests (unit + integration)
npm run lint           # Check code style
npm run format         # Format code

Author

Rob Sweet - President, Superior Technologies Research

A software consulting, contracting, and development company.

License

MIT License - see LICENSE for details.

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Keywords

mcp

FAQs

Package last updated on 01 Jun 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts