The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the ICloud Mail listing page.
A Model Context Protocol (MCP) server for iCloud Mail. Lets an LLM read, search, file and send your Apple mail over IMAP and SMTP.
Runs entirely on your machine: your credentials and your mail never reach a third party. Networking and MIME parsing use only the Python standard library.
SELECT ... readonly and
BODY.PEEK — nothing is marked as read, moved or deleted behind your back.search_all_folders finds them where an inbox-only search can't.save_draft puts a message in Drafts for you to
review. send_email exists, but it is separate and explicit.delete_mailbox refuses any folder that still holds some.Once published to PyPI, no clone is needed:
From source:
The setup command asks for your address and app-specific password, tests the
connection, writes .env, then prints the exact config block for your client.
Generate the app-specific password at account.apple.com → Sign-In and Security → App-Specific Passwords.
Standard config works in most clients:
Check with claude mcp list.
Add the standard config to claude_desktop_config.json:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonOn Windows, use the absolute path to uv.exe: desktop clients don't always
inherit your shell PATH.
In ~/.codex/config.toml:
Use the standard config block in the MCP settings file of your editor
(.cursor/mcp.json, ~/.codeium/windsurf/mcp_config.json, or the VS Code MCP
settings).
MCP servers load at client startup — restart the client after editing its config.
Read — none of these modify the mailbox:
| Tool | Description |
|---|---|
list_folders | List folders, optionally with message and unread counts |
folder_status | Counts for one folder without listing messages |
search_emails | Search one folder: text, sender, recipient, subject, dates, flags, size |
search_all_folders | The same search across every folder at once |
read_email | Full message: decoded body, optional HTML, attachment metadata |
get_thread | Rebuild a conversation, optionally with each message body |
save_attachments | Write attachments to disk and return their paths |
Write — explicit by design:
| Tool | Description |
|---|---|
save_draft | Put a message in Drafts. Nothing is sent |
set_flag | Read/unread, flagged, answered. Reversible |
create_mailbox | Create a folder, accented names included |
rename_mailbox | Rename a folder, messages follow |
delete_mailbox | Delete an empty folder. Refuses while it holds mail |
auto_organize | File messages by rules. Simulates unless dry_run=false |
move_emails | Move between folders. Simulates unless dry_run=false |
send_email | Actually sends. No draft step, no undo |
No tool destroys mail. delete_mailbox refuses a folder that still holds
messages — move them out first, which keeps the decision with you.
Attachment bytes never pass through the model: save_attachments writes files
and returns paths. Filenames arriving from email are sanitised — they are
hostile input, not trusted paths.
| URI | Content |
|---|---|
icloud://folders | Every folder with message and unread counts |
icloud://unread | Unread messages in the inbox |
| Prompt | Purpose |
|---|---|
triage_inbox | Sort recent mail into action required / info / waiting / ignorable |
draft_reply | Read a message and its thread, draft a reply into Drafts |
follow_up | Reconstruct an exchange with a contact, say who owes whom a reply |
examples/ holds standalone scripts using the same modules — point cron or Task
Scheduler at them:
All support --json for piping. See examples/README.md.
skills/mailbox-search/ is a Claude Code skill that forces a sweep of every
folder before concluding a message doesn't exist:
Worth knowing if you're writing your own IMAP client against iCloud:
SEARCH returns UIDs out of order. RFC 3501 doesn't guarantee ordering,
and iCloud genuinely returns unsorted lists. Taking the tail of the response
gives you the wrong messages — sort numerically first.MOVE, no UIDPLUS. Moving means COPY + \Deleted + EXPUNGE, and
EXPUNGE purges every \Deleted message in the folder. move_emails
refuses to run when the folder holds deleted messages outside the requested
batch, which would otherwise be destroyed.SEARCH CHARSET UTF-8 works. Accented queries run server-side across the
whole mailbox. A client-side fallback covers servers that refuse, and flags it
via filtered_client_side in the response.utf7.py.text/plain part..env (gitignored) or the environment, never in code.
Settings.__repr__ omits the password.send_email and move_emails are meant to run only after the user approves
the exact content or the exact message list in the conversation.49 offline tests — no network, no credentials. CI runs them on Linux, macOS and Windows against Python 3.11 to 3.13.
Issues and pull requests welcome. Tests must pass offline — no test may require a real mailbox.
MIT