owlpost

io.github.smankoo由 GitHub 帳號 smankoo 發布v0.3.0更新於 Nov 7, 2026

適用於 iCloud、Gmail、Proton Bridge 等的 IMAP/SMTP 郵件:搜尋、閱讀、跟蹤工作階段、傳送。

AI 翻譯由 AI 模型根據下方的原文描述翻譯,可能有誤。

原文描述

IMAP/SMTP email for iCloud, Gmail, Proton Bridge and more: search, read, follow threads, send.

已驗證STDIO僅桌面效率與工作流溝通與協作

概覽

owlpost 的本機 MCP 服務;無需登入;STDIO;15 個工具。

暫無 AI 概覽:以下資訊來自註冊中心條目和服務本身。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 owlpost,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

owlpost

[PyPI] [CI] [License: MIT] [smankoo/owlpost MCP server]

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.

bash
uvx owlpost

Contents

Features

  • 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 RFC822 fetch returns empty bodies → uses BODY.PEEK[]
    • iCloud's IMAP APPEND requires CRLF line endings → all outbound mail uses policy.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 Messages vs [Gmail]/Sent Mail)
    • Servers without the MOVE extension get COPY + \Deleted + EXPUNGE instead
    • Proton Bridge omits UID from FETCH responses unless asked → owlpost always asks
  • Conversation following — Gmail's X-GM-THRID extension where available, otherwise a generic Message-ID/References BFS across folders
  • Fast, reliable connections — logged-in IMAP sessions are reused for up to a minute (health-checked with NOOP, discarded after any error), every socket has a timeout, and read-only tools retry once if the server drops the connection
  • Typed results — every tool publishes an MCP output schema and returns structured content
  • MIME-aware — parses multipart messages, decodes headers, lists attachments, downloads them to disk
  • Threaded reply/forward — preserves In-Reply-To/References, quotes the original
  • Drafts — compose into the Drafts folder so you can review and send from your own mail client
  • Read-only by default where it matters — searching and reading never mark mail as read
  • Secrets stay out of the config file if you want — password_env and password_command (1Password, pass, Keychain, ...)
  • Annotated tools — every tool declares MCP readOnlyHint / destructiveHint / openWorldHint, so clients can auto-approve reads and ask before sending

Tools

ToolWhat it doesRead-only
list_accountsList configured mail accounts (never includes passwords)✅
list_foldersList folders for an account, with detected special-use roles✅
resolve_folderResolve a role (sent, trash, drafts, inbox, all, archive, ...) to the provider's folder name✅
search_messagesStructured IMAP search (from/to/cc/subject/body/text/since/before/unseen/flagged/has_attachment, or raw), newest first✅
read_emailRead one message: headers, plaintext/HTML body, attachment list. Truncates by default to fit MCP result limits✅
get_conversationReturn all messages in the same thread (Gmail X-GM-THRID or generic reference walking)✅
save_attachmentDownload an attachment to local disk by part index (mailbox untouched)writes local file
send_emailSend mail. Auto-saves to Sent on providers that don't (e.g. iCloud). Supports attachments, threading headers❌ sends
save_draft_emailBuild a message and APPEND it to Drafts without sending — same parameters as send_email❌
reply_emailReply (with optional reply-all), preserving threading and quoting❌ sends
forward_emailForward, re-attaching original attachments by default❌ sends
mark_readSet/unset \Seen❌
flag_messageSet/unset \Flagged (star)❌
move_emailMove to another folder❌ destructive
delete_emailMove to Trash (not expunged)❌ destructive

Every tool takes an account argument (the name from list_accounts). Messages are addressed by folder + uid, as returned by search_messages.

Install

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:

bash
uvx owlpost            # speaks MCP over stdiouvx owlpost --version

If you'd rather have a stable binary on your PATH:

bash
uv tool install owlpost   # or: pipx install owlpost / pip install owlpost

There's also a container image, see Docker.

Configure

Copy accounts.example.toml to ~/.config/owlpost/accounts.toml and fill in your credentials. Use app-specific passwords, not your real password:

toml
[accounts.icloud]email = "[email protected]"password_command = "op read op://Private/iCloud Mail/app-password"provider = "icloud"imap_host = "imap.mail.me.com"smtp_host = "smtp.mail.me.com"auto_save_sent = true   # iCloud SMTP doesn't auto-save sent
[accounts.gmail]email = "[email protected]"password_env = "OWLPOST_GMAIL_PASSWORD"provider = "gmail"imap_host = "imap.gmail.com"smtp_host = "smtp.gmail.com"auto_save_sent = false  # Gmail SMTP auto-saves

The table name (icloud, gmail above) is what you pass as account to the tools.

Where the config lives

In order of precedence:

  1. owlpost --config /path/to/accounts.toml
  2. the OWLPOST_CONFIG environment variable
  3. ~/.config/owlpost/accounts.toml

The file is read on the first tool call; restart the server after editing it.

Reference

KeyRequiredDefaultMeaning
email✅Login username and the From address
passwordone of threePassword inline (app password recommended)
password_envone of threeName of an environment variable holding the password
password_commandone of threeCommand that prints the password, e.g. op read op://...
providergenericicloud, gmail or generic. gmail enables X-GM-THRID threading
imap_host✅IMAP server hostname
imap_port993IMAP port
imap_securitysslssl (implicit TLS, usually 993) or starttls (usually 143 / 1143)
smtp_host✅SMTP server hostname
smtp_port587SMTP port
smtp_securitystarttlsstarttls (usually 587) or ssl (usually 465)
auto_save_senttrueAPPEND a copy of sent mail to the Sent folder. Turn off for Gmail
tls_verifytrueVerify TLS certificates. Set false only for local bridges with self-signed certs

Exactly one of password, password_env and password_command must be set.

password_command is split with shell-like quoting rules and run directly (no shell, so no pipes or $VARS), with a 10 second timeout. Its stdout, minus the trailing newline, is the password. It runs the first time the account is used and the result is cached for the life of the server process. If it fails, the tool call returns an error with the command's exit code and stderr. Some examples:

toml
password_command = "op read op://Private/Fastmail/app-password"                  # 1Password CLIpassword_command = "pass show mail/fastmail"                                     # passpassword_command = "security find-generic-password -s owlpost-icloud -w"         # macOS Keychainpassword_command = "secret-tool lookup service owlpost account icloud"           # GNOME Keyring

password_env reads the variable from the server's environment, which your MCP client controls (the env block in the snippets below).

Client setup

All of these run uvx owlpost. If your client can't find uvx, use the absolute path (typically ~/.local/bin/uvx, see which uvx). If you installed with uv tool install, you can use owlpost as the command instead.

Claude Desktop

One-click: download owlpost-<version>.mcpb from the latest release and open it. Claude Desktop installs it and asks for the path to your accounts.toml.

Manual:

Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Windows: %APPDATA%\Claude\claude_desktop_config.json):

json
{  "mcpServers": {    "owlpost": {      "command": "uvx",      "args": ["owlpost"]    }  }}

Claude Code

bash
claude mcp add owlpost --scope user -- uvx owlpost
# with a non-default config path, or a password from the environmentclaude mcp add owlpost --scope user \  -e OWLPOST_CONFIG=/path/to/accounts.toml \  -- uvx owlpost

Cursor

Add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):

json
{  "mcpServers": {    "owlpost": {      "command": "uvx",      "args": ["owlpost"]    }  }}

VS Code

Add to .vscode/mcp.json in your workspace (or run MCP: Add Server for a user-level install):

json
{  "servers": {    "owlpost": {      "type": "stdio",      "command": "uvx",      "args": ["owlpost"]    }  }}

Other MCP clients

owlpost speaks the standard MCP stdio transport — any MCP-compatible client can talk to it by spawning uvx owlpost or the installed owlpost binary. Pass env: {"OWLPOST_CONFIG": "..."} to point it at a config file.

Docker

The image expects the config at /config/accounts.toml. Mount the directory that contains it, read-only:

bash
docker run -i --rm \  --mount type=bind,src="$HOME/.config/owlpost",dst=/config,readonly \  ghcr.io/smankoo/owlpost:latest

As an MCP client entry:

json
{  "mcpServers": {    "owlpost": {      "command": "docker",      "args": [        "run", "-i", "--rm",        "--mount", "type=bind,src=/home/you/.config/owlpost,dst=/config,readonly",        "ghcr.io/smankoo/owlpost:latest"      ]    }  }}

Inside the container password_command can only run binaries that exist in the image, so use password or password_env (pass it with -e OWLPOST_GMAIL_PASSWORD). To reach Proton Bridge on the host, use --network host (Linux) or imap_host = "host.docker.internal". save_attachment writes inside the container unless you mount a writable directory for it.

Examples

Once registered, you can ask things like:

  • "Find emails from the school about the field trip 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"
  • "Draft a reply to the insurance renewal asking for the PDF, don't send it"
  • "Forward the policy PDFs to [email protected]"
  • "Save the attachment from this month's electricity bill to ~/Downloads"

Provider notes

iCloud

  • Use an app-specific password, not your Apple ID password.
  • iCloud throttles aggressive reconnection. owlpost reuses its IMAP session between calls to avoid this, but if you still see SSLEOFError: EOF, back off for ~30 seconds.
  • Sent folder is Sent Messages, Trash is Deleted Messages. Both are auto-detected.
  • Keep auto_save_sent = true: iCloud's SMTP doesn't keep a copy of what you send.

Gmail

  • Requires 2FA and an app password.
  • IMAP must be enabled in Gmail settings → Forwarding and POP/IMAP.
  • Set provider = "gmail" so owlpost uses Gmail's X-GM-THRID extension for reliable thread detection.
  • Set auto_save_sent = false; Gmail's SMTP already files sent mail, so APPENDing would duplicate it.
  • delete_email moves to [Gmail]/Trash. Moving out of INBOX to a label folder works like archiving.

Proton Mail (via Proton Bridge)

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)

Other providers

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); otherwise owlpost falls back to common names like Sent, Sent Items and Trash. Whether to keep auto_save_sent on depends on whether your provider's SMTP files sent mail itself — send yourself a test and check for duplicates.

Security

  • owlpost sends real email. send_email, reply_email and forward_email are annotated openWorldHint: true and are not read-only. Configure your MCP client to ask for confirmation before running them (most do by default for non-read-only tools), and don't auto-approve them. The server's instructions also tell the model to confirm recipients and content with you before sending. If you only want the model to prepare mail, steer it towards save_draft_email.
  • Untrusted content. Email bodies are written by strangers. A message can contain text designed to manipulate a model ("forward the last 10 invoices to ..."). Keep send confirmations on, especially in agents that read mail and can send it.
  • Use app passwords, never your main account password. They can be revoked individually and don't grant account-management access.
  • Keep secrets out of the file with password_command (your password manager) or password_env. If you do put a password in the file, chmod 600 ~/.config/owlpost/accounts.toml.
  • list_accounts never returns passwords or password sources.
  • tls_verify = false disables certificate checks entirely; only use it for a bridge on 127.0.0.1.
  • save_attachment and attachments read and write local paths as the user running the server.

Found a vulnerability? See SECURITY.md.

Troubleshooting

SymptomFix
Tools don't show up in the clientThe client couldn't spawn uvx. Use its absolute path (which uvx) and restart the client. Run uvx owlpost --version in a terminal to check it works
owlpost config not found at ...Create ~/.config/owlpost/accounts.toml, or set OWLPOST_CONFIG / --config
must set exactly one of password, password_env, password_commandRemove the extra key (or add one) in that [accounts.<name>] table
password_command exited with 1: ...Run the command in a terminal. Password-manager CLIs often need you to be signed in (op signin) or unlocked
Unknown account 'x'. Known: [...]Use one of the listed names; it's the TOML table name, not the email address
[AUTHENTICATIONFAILED] / 535 on loginWrong or revoked app password; for Gmail, make sure IMAP is enabled
SSLEOFError: EOF on iCloudiCloud throttling reconnects; wait ~30 seconds
CERTIFICATE_VERIFY_FAILED with Proton BridgeSet tls_verify = false for that account
Sent mail appears twiceYour provider already saves sent mail; set auto_save_sent = false
Sent mail missing from SentSet auto_save_sent = true
unknown encoding: idnaUpgrade to owlpost 0.1.4 or later

Development

bash
git clone https://github.com/smankoo/owlpostcd owlpostuv sync                      # creates .venv with dev toolsuv run pytest                # tests use fake IMAP/SMTP, no networkuv run ruff check .uv run ruff format --check .uv run python scripts/smoke_stdio.py uv run owlpost   # stdio handshake + tools/list

See CONTRIBUTING.md for the release process and CHANGELOG.md for history.

License

MIT — see LICENSE.

來源:README.md,提交 9597583

工具

15

list_accounts

List accounts

List the mail accounts configured in owlpost's accounts.toml. Returns one entry per account with its `name` (the value to pass as `account` to every other tool), email address, provider (icloud, gmail or generic), IMAP/SMTP hostnames and whether sent mail is auto-saved. Passwords and password sources are never included. Takes no arguments and does not contact any mail server.

無需輸入參數。

list_folders

List folders

List every IMAP folder (mailbox) in an account. Each entry has the folder `name` to use in other tools, its raw IMAP flags, the hierarchy delimiter, and a detected `role` (inbox, sent, trash, drafts, junk, archive, all, flagged, important) based on RFC 6154 SPECIAL-USE flags, or null for ordinary folders. Args: account: Account name from list_accounts.

輸入參數account必填

resolve_folder

Resolve folder role

Resolve a special-use role to the provider-specific folder name. For example "sent" becomes "Sent Messages" on iCloud and "[Gmail]/Sent Mail" on Gmail. Uses SPECIAL-USE flags first and falls back to common folder names. Returns null if no matching folder exists. Args: account: Account name from list_accounts. role: One of inbox, sent, trash, drafts, junk, archive, all, flagged or important (case-insensitive).

輸入參數role必填account必填

search_messages

Search messages

Search one folder with structured filters and return message envelopes, newest first. All filters are combined with AND. String filters use IMAP case-insensitive substring matching; multi-word values are quoted for you. Each result has uid, folder, message_id, subject, from/to/cc, date, flags, size, seen and flagged; pass folder + uid to read_email for the body. The folder is opened read-only, so searching never marks mail read. Args: account: Account name from list_accounts. folder: Folder to search (default "INBOX"); use list_folders or resolve_folder for others. from_: Substring of the From header (name or address). to: Substring of the To header. cc: Substring of the Cc header. subject: Substring of the Subject. body: Substring of the message body. text: Substring of headers or body. since: Only messages on or after this date (YYYY-MM-DD). before: Only messages before this date (YYYY-MM-DD). unseen: Only unread messages. seen: Only read messages. flagged: Only flagged/starred messages. has_attachment: Best-effort filter for messages with attachments (multipart/mixed or an attachment disposition header). raw: A raw IMAP SEARCH string, e.g. 'OR FROM "alice" FROM "bob"'. When set, every other filter is ignored. limit: Maximum number of results (default 50).

輸入參數cctorawbodyseentextfrom_limitsincebeforefolderunseen另有 4 個

read_email

Read email

Read one message: decoded headers, body and attachment list, without marking it read. By default only the plain-text body is returned, truncated at 50,000 characters to fit MCP result limits; the untruncated sizes are always reported as text_full_length and html_full_length. Attachments are listed with a 1-based `part` index for save_attachment. Threading headers (message_id, in_reply_to, references) are included. Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID from search_messages. include_html: Also return the HTML body (default false). HTML mail can be very large. include_text: Return the plain-text body (default true). body_max_chars: Truncate each body to this many characters (default 50000).

輸入參數uid必填folder必填account必填include_htmlinclude_textbody_max_chars

save_attachment

Save attachment

Download one attachment from a message and write it to the local filesystem. The mailbox is not modified. Returns the written path, size, MIME type and original filename. An existing file at the target path is overwritten. Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. part: 1-based part index from read_email's `attachments` list. save_to: Destination. A directory (trailing slash, existing directory, or a path without an extension) keeps the original filename; anything else is used as the full file path. `~` is expanded and missing directories are created.

輸入參數uid必填part必填folder必填account必填save_to必填

get_conversation

Get conversation

Return every message in the same conversation as a given message, oldest first. On Gmail this uses the X-GM-THRID thread id across All Mail. Elsewhere it follows the Message-ID / In-Reply-To / References graph across the inbox, sent, archive, all-mail and drafts folders, so your own replies are included. Returns envelopes (no bodies); use read_email for content. Identify the seed message with either `message_id`, or `folder` + `uid`. Args: account: Account name from list_accounts. message_id: Message-ID header of any message in the thread, including angle brackets. folder: Folder of the seed message (used with uid). uid: UID of the seed message (used with folder).

輸入參數uidfolderaccount必填message_id

send_email

Send email

Send a new email over SMTP immediately; this cannot be undone, so confirm with the user first. When the account has auto_save_sent enabled (needed for iCloud, whose SMTP does not keep a copy) the message is also appended to the Sent folder. Returns the generated Message-ID, recipients and the folder the copy was saved to (null if none). To answer an existing message prefer reply_email, which fills in recipients and threading for you. Args: account: Account name from list_accounts; mail is sent from its address. to: Recipient email addresses. subject: Subject line. body: Plain-text body. cc: Cc recipient addresses. bcc: Bcc recipient addresses (delivered but never written to headers). html: Optional HTML alternative to the plain-text body. attachments: Local file paths to attach. in_reply_to: Message-ID this message replies to, for threading. references: Message-IDs of earlier messages in the thread.

輸入參數ccto必填bccbody必填htmlaccount必填subject必填referencesattachmentsin_reply_to

save_draft_email

Save draft

Compose an email and save it to the account's Drafts folder without sending it. The message is appended to the special-use Drafts folder with the \Draft flag, so the user can review, edit and send it from their own mail client. Use this instead of send_email whenever the user wants to check a message first. Each call creates a new draft. Args: account: Account name from list_accounts. to: Recipient email addresses. subject: Subject line. body: Plain-text body. cc: Cc recipient addresses. bcc: Bcc recipient addresses. html: Optional HTML alternative to the plain-text body. attachments: Local file paths to attach. in_reply_to: Message-ID this draft replies to, for threading. references: Message-IDs of earlier messages in the thread.

輸入參數ccto必填bccbody必填htmlaccount必填subject必填referencesattachmentsin_reply_to

reply_email

Reply to email

Reply to a message and send the reply immediately; confirm with the user first. Addresses the reply to the original sender (plus the original To/Cc, minus your own address, when reply_all is true), prefixes the subject with "Re:" if needed, sets In-Reply-To and References so clients thread it correctly, and quotes the original plain-text body below yours. Args: account: Account name from list_accounts. folder: Folder containing the message being answered. uid: UID of the message being answered. body: Your reply text; the quoted original is appended after it. reply_all: Also reply to the original To and Cc recipients. html: Optional HTML alternative for the reply. attachments: Local file paths to attach.

輸入參數uid必填body必填htmlfolder必填account必填reply_allattachments

forward_email

Forward email

Forward a message to new recipients and send it immediately; confirm with the user first. The subject gets a "Fwd:" prefix, the original headers and plain-text body are included below your note, and the original attachments are re-attached unless include_attachments is false. Args: account: Account name from list_accounts. folder: Folder containing the message to forward. uid: UID of the message to forward. to: Recipient email addresses. body: Optional note placed above the forwarded content. cc: Cc recipient addresses. bcc: Bcc recipient addresses. attachments: Extra local file paths to attach. include_attachments: Re-attach the original message's attachments (default true).

輸入參數ccto必填bccuid必填bodyfolder必填account必填attachmentsinclude_attachments

mark_read

Mark read/unread

Mark a message as read or unread by setting or clearing its \Seen flag. Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. read: True to mark read (default), false to mark unread.

輸入參數uid必填readfolder必填account必填

flag_message

Flag message

Flag (star) or unflag a message by setting or clearing its \Flagged flag. Args: account: Account name from list_accounts. folder: Folder containing the message. uid: Message UID. flagged: True to flag (default), false to remove the flag.

輸入參數uid必填folder必填account必填flagged

move_email

Move email

Move a message from one folder to another. Uses IMAP MOVE when the server supports it, otherwise COPY followed by flagging the original \Deleted and EXPUNGE. The message gets a new UID in the destination folder, so the old uid is no longer valid afterwards. Args: account: Account name from list_accounts. folder: Folder the message is currently in. uid: Message UID in that folder. dest_folder: Destination folder name (see list_folders).

輸入參數uid必填folder必填account必填dest_folder必填

delete_email

Delete email

Delete a message by moving it to the account's Trash folder. The Trash folder is discovered via SPECIAL-USE (e.g. "Deleted Messages" on iCloud, "[Gmail]/Trash" on Gmail). The message is not permanently expunged from Trash, so it can still be recovered from the mail client. Args: account: Account name from list_accounts. folder: Folder the message is currently in. uid: Message UID in that folder.

輸入參數uid必填folder必填account必填

版本歷史

2
  1. v0.3.0最新Nov 3, 2026
  2. v0.2.0Oct 18, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分