A high-fidelity IMAP/SMTP MCP server for iCloud, Gmail, and other mail
providers. Built because every other email MCP server I tried got tripped up
by real-world IMAP quirks (CRLF line endings, RFC822 vs BODY.PEEK[],
provider-specific Sent folders, multi-word search values).
owlpost is the one I actually use day-to-day from Claude Code to read, search, follow conversations, and send mail.
- Multi-account — configure as many mailboxes as you want, switch by name
- iCloud and Gmail tested end-to-end, with provider-specific quirks handled:
- iCloud's
RFC822fetch returns empty bodies → usesBODY.PEEK[] - iCloud's IMAP
APPENDrequires CRLF line endings → all outbound mail usespolicy.SMTP - iCloud's SMTP doesn't auto-save sent mail → owlpost APPENDs to Sent for you
- Gmail's SMTP does auto-save → owlpost skips the duplicate APPEND
- Folder names auto-discovered via RFC 6154 SPECIAL-USE (no hardcoding
Sent Messagesvs[Gmail]/Sent Mail)
- iCloud's
- Conversation following — Gmail's
X-GM-THRIDextension where available, otherwise a generic Message-ID/References BFS across folders - Reliable connections — short-lived per-operation IMAP sessions instead of long-lived ones that drop randomly
- MIME-aware — parses multipart messages, decodes headers, lists attachments, downloads them to disk
- Threaded reply/forward — preserves
In-Reply-To/References, quotes the original
| Tool | What it does |
|---|---|
list_accounts |
List configured mail accounts |
list_folders |
List folders for an account, with detected special-use roles |
resolve_folder |
Resolve a role (sent, trash, drafts, inbox, all, archive) to a folder name |
search_messages |
Structured IMAP search (from/to/cc/subject/body/since/before/unseen/flagged/has_attachment), newest first |
read_email |
Read one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits |
save_attachment |
Download an attachment to disk by part index |
get_conversation |
Return all messages in the same thread (Gmail X-GM-THRID or generic reference walking) |
send_email |
Send mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers |
save_draft_email |
Build a message and APPEND it to Drafts without sending — same parameters as send_email |
reply_email |
Reply (with optional reply-all), preserving threading and quoting |
forward_email |
Forward, re-attaching original attachments by default |
mark_read |
Set/unset \Seen |
flag_message |
Set/unset \Flagged (star) |
move_email |
Move to another folder |
delete_email |
Move to Trash |
The recommended way is to not install at all — let
uvx fetch and cache it on first
use. This keeps the package always up-to-date and avoids polluting your
global Python environment:
# Run directly — uvx fetches from PyPI and caches.
uvx --from owlpost owlpostIf you'd rather have a stable binary on your PATH:
# Persistent install with uv (recommended)
uv tool install owlpost
# Or plain pip
pip install owlpostEither way you'll end up with an owlpost command that speaks MCP over stdio.
Copy accounts.example.toml to
~/.config/owlpost/accounts.toml and fill in your credentials. Use
app-specific passwords, not your real password:
- iCloud: account.apple.com → Sign-In and Security → App-Specific Passwords
- Gmail: myaccount.google.com/apppasswords (2FA must be enabled)
[accounts.icloud]
email = "you@icloud.com"
password = "xxxx-xxxx-xxxx-xxxx"
provider = "icloud"
imap_host = "imap.mail.me.com"
imap_port = 993
smtp_host = "smtp.mail.me.com"
smtp_port = 587
auto_save_sent = true # iCloud SMTP doesn't auto-save sent
[accounts.gmail]
email = "you@gmail.com"
password = "xxxx xxxx xxxx xxxx"
provider = "gmail"
imap_host = "imap.gmail.com"
imap_port = 993
smtp_host = "smtp.gmail.com"
smtp_port = 587
auto_save_sent = false # Gmail SMTP auto-savesYou can override the config path with the OWLPOST_CONFIG environment
variable.
Add to ~/.claude.json under mcpServers. The uvx form is recommended —
it fetches owlpost from PyPI on first launch, caches it, and keeps you on
the latest version with no manual install step:
{
"mcpServers": {
"owlpost": {
"type": "stdio",
"command": "uvx",
"args": ["--from", "owlpost", "owlpost"],
"env": {}
}
}
}If uvx isn't on Claude Code's PATH you may need to use the absolute
path (typically ~/.local/bin/uvx).
Alternatively, if you installed with uv tool install owlpost or
pip install owlpost, point command directly at the resulting binary:
{
"mcpServers": {
"owlpost": {
"type": "stdio",
"command": "owlpost",
"args": [],
"env": {}
}
}
}Restart Claude Code and the tools will appear under the owlpost namespace.
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"owlpost": {
"command": "uvx",
"args": ["--from", "owlpost", "owlpost"]
}
}
}owlpost speaks the standard MCP stdio transport — any MCP-compatible client
can talk to it by spawning either uvx --from owlpost owlpost or, if
installed, the bare owlpost binary.
Once registered, you can ask Claude things like:
- "Find emails from priya about the kids' school in the last month"
- "Show me the full thread for the latest mortgage email"
- "Reply to the most recent message from the landlord saying I'll be in touch tomorrow"
- "Forward the Manulife policy PDFs to Mom and Dad with Priyanka in CC"
- "Save the attachment from the Toronto Hydro bill to ~/Downloads"
- Use an app-specific password, not your Apple ID password.
- iCloud throttles aggressive reconnection. owlpost uses short-lived per-op sessions but doesn't pool — if you get
SSLEOFError: EOF, back off for ~30 seconds. - Sent folder is
Sent Messages, Trash isDeleted Messages. Both are auto-detected.
- Requires 2FA and an app password.
- IMAP must be enabled in Gmail settings → Forwarding and POP/IMAP.
- owlpost uses Gmail's
X-GM-THRIDextension for reliable thread detection.
Proton only exposes IMAP/SMTP through the Proton Bridge app, which runs on localhost with a self-signed certificate and speaks STARTTLS on non-standard ports. Configure with:
provider = "generic"imap_host = "127.0.0.1",imap_port = 1143,imap_security = "starttls"smtp_host = "127.0.0.1",smtp_port = 1025,smtp_security = "starttls"tls_verify = false— required because Bridge's cert is self-signed- Use the Bridge-generated mailbox password (not your Proton account password)
Set provider = "generic" and configure imap_host, smtp_host, ports,
imap_security / smtp_security (starttls or ssl), and tls_verify
(set false for self-signed certs). Folder roles will still be
auto-detected if your provider supports SPECIAL-USE (most modern ones do).
git clone https://github.com/smankoo/owlpost
cd owlpost
uv venv
uv pip install -e .Run the server directly to verify it starts:
.venv/bin/owlpost
# (waits for MCP stdio input)Releases go to PyPI. From a clean tree
on main:
# 1. Bump version in pyproject.toml
# 2. Commit the bump
# 3. Build the sdist + wheel
uv build
# 4. Upload to PyPI (requires ~/.pypirc with an API token)
uv publish
# 5. Tag and push
git tag v0.1.x
git push && git push --tagsuv build writes to dist/. uv publish reads credentials from
~/.pypirc (expects [pypi] with username = __token__ and
password = pypi-...). uvx users pick up the new version automatically
on next launch.
MIT — see LICENSE.