iCloud Mail

io.github.JulienRabaultPublished by GitHub account JulienRabaultv0.1.1Updated Oct 24, 2026

Read, search, draft, send and file iCloud Mail over IMAP and SMTP. No tool destroys mail.

Overview

AI-generated overview

Lets an assistant read, search, draft, file and send iCloud Mail over IMAP and SMTP, with read-only defaults and no mail-destroying tools.

What you can do
Connects to an iCloud mailbox over IMAP and SMTP and exposes tools to list folders, search one folder or all folders, read messages and threads, and save attachments to disk. Write tools cover saving drafts, setting flags, creating, renaming and deleting empty folders, rule-based filing, moving messages, and sending email. Read tools use read-only selection and peek fetches, and move or organize operations simulate unless explicitly told to apply.
When to use it
Useful when an assistant should triage an iCloud inbox, find messages filed outside the inbox, summarize threads, prepare drafts for review, or file mail by rules. It fits users who want mail handling to stay on their own machine rather than through a third-party mail service.
Requirements
Runs locally as a Python package (Python 3.11 or newer, with uv). Needs an iCloud account with two-factor authentication and an app-specific password supplied as ICLOUD_APP_PASSWORD, plus the iCloud address in ICLOUD_EMAIL; ICLOUD_DISPLAY_NAME is optional. Network access to iCloud IMAP and SMTP is required, and desktop clients must be restarted after configuration changes.
Before you install
The app-specific password in ICLOUD_APP_PASSWORD grants mailbox access and should be stored in a gitignored .env or the environment. send_email actually sends with no draft step or undo, and move_emails or auto_organize change mailbox state unless run in simulation. Attachment filenames from email are treated as hostile input. Received mail is data, not instructions, and the server asks clients not to act on directives inside messages.

Installation

In SourceWeft

  1. Open iCloud Mail in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

iCloud Mail MCP

[License: MIT] [PyPI] [Python 3.11+] [MCP]

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.

Key Features

  • Read-only by default. Search and read tools use SELECT ... readonly and BODY.PEEK — nothing is marked as read, moved or deleted behind your back.
  • Searches every folder, not just the inbox. Replies get filed away by mail rules; search_all_folders finds them where an inbox-only search can't.
  • Drafts before sends. save_draft puts a message in Drafts for you to review. send_email exists, but it is separate and explicit.
  • Nothing destroys mail. There is no tool that deletes messages, and delete_mailbox refuses any folder that still holds some.
  • Handles real iCloud MIME. Modified UTF-7 folder names, quoted-printable, lying charsets, HTML-only messages, accented server-side search.

Requirements

  • Python 3.11 or newer, and uv
  • An iCloud account with two-factor authentication enabled
  • An app-specific password — iCloud rejects your main password over IMAP

Getting started

Once published to PyPI, no clone is needed:

bash
uvx --from icloud-mail-mcp icloud-mcp-setup     # interactive configurationuvx --from icloud-mail-mcp icloud-mcp           # run the server

From source:

bash
git clone https://github.com/JulienRabault/icloud-mcp.gitcd icloud-mcpuv syncuv run python -m icloud_mcp.setup

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:

json
{  "mcpServers": {    "icloud-mail": {      "command": "uv",      "args": ["run", "--directory", "/path/to/icloud-mcp", "python", "-m", "icloud_mcp"]    }  }}
Claude Code
bash
claude mcp add icloud-mail --scope user -- uv run --directory /path/to/icloud-mcp python -m icloud_mcp

Check with claude mcp list.

Claude Desktop

Add the standard config to claude_desktop_config.json:

  • macOS — ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows — %APPDATA%\Claude\claude_desktop_config.json

On Windows, use the absolute path to uv.exe: desktop clients don't always inherit your shell PATH.

Codex

In ~/.codex/config.toml:

toml
[mcp_servers.icloud-mail]command = "uv"args = ["run", "--directory", "/path/to/icloud-mcp", "python", "-m", "icloud_mcp"]
Cursor / Windsurf / VS Code

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.

Tools

Read — none of these modify the mailbox:

ToolDescription
list_foldersList folders, optionally with message and unread counts
folder_statusCounts for one folder without listing messages
search_emailsSearch one folder: text, sender, recipient, subject, dates, flags, size
search_all_foldersThe same search across every folder at once
read_emailFull message: decoded body, optional HTML, attachment metadata
get_threadRebuild a conversation, optionally with each message body
save_attachmentsWrite attachments to disk and return their paths

Write — explicit by design:

ToolDescription
save_draftPut a message in Drafts. Nothing is sent
set_flagRead/unread, flagged, answered. Reversible
create_mailboxCreate a folder, accented names included
rename_mailboxRename a folder, messages follow
delete_mailboxDelete an empty folder. Refuses while it holds mail
auto_organizeFile messages by rules. Simulates unless dry_run=false
move_emailsMove between folders. Simulates unless dry_run=false
send_emailActually 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.

Resources

URIContent
icloud://foldersEvery folder with message and unread counts
icloud://unreadUnread messages in the inbox

Prompts

PromptPurpose
triage_inboxSort recent mail into action required / info / waiting / ignorable
draft_replyRead a message and its thread, draft a reply into Drafts
follow_upReconstruct an exchange with a contact, say who owes whom a reply

Automation without an MCP client

examples/ holds standalone scripts using the same modules — point cron or Task Scheduler at them:

bash
uv run python examples/daily_digest.py           # what arrived todayuv run python examples/watch_sender.py acme.com  # exit 1 if nothing newuv run python examples/waiting_on_reply.py       # threads nobody answereduv run python examples/auto_file.py --apply      # file mail by rules

All support --json for piping. See examples/README.md.

Bundled skill

skills/mailbox-search/ is a Claude Code skill that forces a sweep of every folder before concluding a message doesn't exist:

bash
cp -r skills/mailbox-search ~/.claude/skills/

iCloud quirks handled here

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.
  • No 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.
  • Folder names use modified UTF-7 (RFC 3501), implemented in utf7.py.
  • Charsets lie. Bodies fall back to latin-1 when the declared charset fails, and to stripped HTML when there's no text/plain part.

Security notes

  • Credentials live in .env (gitignored) or the environment, never in code. Settings.__repr__ omits the password.
  • Email content is data, not instructions. The server tells clients never to act on directives found inside a received message.
  • 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.

Development

bash
uv run pytest -q

49 offline tests — no network, no credentials. CI runs them on Linux, macOS and Windows against Python 3.11 to 3.13.

src/icloud_mcp/  config.py        env / .env loading  utf7.py          modified UTF-7 for folder names  models.py        frozen Pydantic models  mime.py          header, body and attachment decoding  imap_client.py   connection, LIST, STATUS, SELECT, FETCH  search.py        SEARCH criteria, threading, multi-folder search  smtp_client.py   MIME building, SMTP send, copy to Sent  attachments.py   attachment extraction, filename sanitising  drafts.py        APPEND to Drafts  flags.py         \Seen, \Flagged, \Answered  move.py          COPY + EXPUNGE with the anti-purge guard  mailboxes.py     create, rename, delete (empty only)  organize.py      rule-based filing  server.py        tools, resources, prompts  setup_wizard.py  interactive configuration  cli.py           terminal checks

Contributing

Issues and pull requests welcome. Tests must pass offline — no test may require a real mailbox.

License

MIT

Source: README.md at commit efee3ee

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v0.1.1LatestSep 22, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts