
Email Mcp
io.github.codefuturist由 GitHub 账号 codefuturist 发布v0.6.0更新于 Oct 24, 2026
IMAP/SMTP email MCP server — 52 tools, stdio + HTTP, IMAP IDLE push, multi-account, AI triage.
概览
IMAP/SMTP 邮件服务器,让助手读取、搜索、发送、回复和整理多个账户的邮件,提供 52 个工具和 AI 分拣。
- 可以做什么
- 列出、读取、搜索邮件并浏览邮箱文件夹,支持 JSON 输出
- 发送、回复和定时发送邮件,受附件大小限制并可保存到已发送文件夹
- 标记、删除邮件并下载附件
- 管理多个账户、测试连接并配置 IMAP/SMTP 参数
- 可作为 stdio 服务器、Streamable HTTP 服务器或带 IMAP IDLE 推送的后台常驻服务运行
- 适用场景
- 适合让助手直接操作真实邮箱:整理收件箱、查找邮件、起草回复或带附件发信,可跨一个或多个账户。也适合需要常驻监听而非随客户端会话结束的场景。
- 运行要求
- npm 包需要 Node.js 24 或更高版本,也可改用预编译二进制、Homebrew cask 或 Docker 镜像。每个账户需要 IMAP 与 SMTP 主机设置以及密码或应用专用密码,可存于配置文件、系统钥匙串、环境变量,单账户也可用 MCP_EMAIL_* 变量。Gmail 与 Microsoft 365 的 OAuth2 为实验性功能。
安装
在 SourceWeft 中
- 打开 控制台中的 Email Mcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
Email MCP Server
[standard-readme compliant] [license] [npm version] [npm downloads] [CI]
An MCP (Model Context Protocol) server providing comprehensive email capabilities via IMAP and SMTP.
Enables AI assistants to read, search, send, manage, schedule, and analyze emails across multiple accounts. Exposes 52 tools, 7 prompts, and 6 resources over the MCP protocol with OAuth2 support (experimental), email scheduling, calendar extraction, analytics, provider-aware label management, real-time IMAP IDLE watcher with AI-powered triage, instant verification-code catching with clipboard copy, customizable presets and static rules, and a guided setup wizard.
Built on the MCP TypeScript SDK v2 (spec revision 2026-07-28), it serves over stdio for local clients or Streamable HTTP for networked access — existing stdio configurations keep working unchanged.
Highlights
Table of Contents
Security
- All connections use TLS/STARTTLS encryption
- Passwords are never logged; audit trail records operations without credentials
- Token-bucket rate limiter prevents abuse (one bucket per account, sharing a global
rate_limit) - OAuth2 XOAUTH2 authentication for Gmail and Microsoft 365 (experimental)
- Attachment downloads capped at 5 MB with base64 encoding
Background
Most MCP email implementations provide only basic read/send. This server aims to be a full-featured email client for AI assistants, covering the entire lifecycle: reading, composing, managing, scheduling, and analyzing email — all from a single MCP server.
Key design decisions:
- XDG-compliant config — TOML at
~/.config/email-mcp/config.toml - Multi-account — Operate across multiple IMAP/SMTP accounts simultaneously
- Layered services — Business logic is decoupled from MCP wiring for testability
- Provider auto-detection — Gmail, Outlook, Yahoo, iCloud, Fastmail, ProtonMail, Zoho, GMX
Install
Requires Node.js ≥ 24.
npm install -g fails with EACCES when npm's global prefix is a root-owned
directory (common on a system Node install) — the npx/pnpm dlx form above
avoids this entirely by not installing anything globally. If you do want a
permanent global install, fix npm's prefix instead of reaching for sudo
(npm config set prefix ~/.npm-global and add that to PATH, or use a Node
version manager like nvm/fnm/volta) — running npm install -g as root
routinely leaves root-owned files mixed into a user-owned node_modules tree,
which causes harder-to-diagnose permission errors on the next global install.
Homebrew (native binary)
The prebuilt, dependency-free binary — no Node.js at runtime — from the codefuturist tap:
Published as a cask on every stable release; works on macOS (arm64 + x64) and on Linuxbrew ≥ 4.3 (binary-only casks).
Native binary (Bun)
A dependency-free single binary (minified + bytecode-precompiled, ~32 ms cold start, no Node.js at runtime) can be compiled with Bun:
Prebuilt binaries for every release are built by CI with GoReleaser Pro
(.goreleaser.yaml) for all common platforms — Linux glibc + musl, macOS, and
Windows, each x64 + arm64 where Bun supports it — provenance-attested (verify with
gh attestation verify <asset> --repo codefuturist/email-mcp) and shipped with
GitHub releases —
installable via mise: mise use -g ubi:codefuturist/email-mcp.
The same binary can also be built locally from the published npm package (no
checkout needed; ≥ 0.5.1, which carries the imapflow TLS fix at runtime —
older versions need the repo's pnpm patch). Note that a plain bun add -g
shim executes dist/main.js under node via its shebang, so the compile step
is what buys the ~11 ms cold start:
An installed binary keeps itself current: email-mcp update checks the latest
release and — after a confirmation, a sha256 check against the release's
checksums file, and (when the gh CLI is present) a provenance-attestation
check — atomically replaces itself. --check only reports (exit code 1 =
update available), --yes skips the prompt for scripts. npm- and mise-managed
installs are recognized and pointed at npm install -g …@latest /
mise upgrade instead of being overwritten.
server install from the binary points the launchd login item at it. Requires the
bundled imapflow patch (patches/) — imapflow passes servername: false to
tls.connect for IP hosts, which Bun's stricter node:tls rejects.
Docker
No Node.js required — just Docker.
Tag convention: Tags follow bare semver (no
vprefix), matching Docker ecosystem standards (e.g.node:24,nginx:1.25). Thelatesttag is only updated on stable releases, never pre-releases.
Note: By default, the server uses stdio transport. Config must be created on the host first (via
npx @codefuturist/email-mcp setupor manually) and mounted into the container.
Usage
Setup
The setup wizard auto-detects server settings, tests connections, saves config, and outputs the MCP client config snippet.
Test Connections
Configure Your MCP Client
The snippets below use the default stdio transport, best for local desktop clients. For networked or remote access over Streamable HTTP, see Streamable HTTP (networked) below.
Recommended — use the guided installer (auto-detects Claude Desktop, Cursor, Windsurf; for VS Code use the manual snippet below):
Or add manually using the snippets below.
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
VS Code (GitHub Copilot)
Option 1 — Extensions gallery (easiest):
- Open the Extensions view (⇧⌘X / Ctrl+Shift+X)
- Search
@mcp email-mcp - Click Install (user-wide) or right-click → Install in Workspace
Option 2 — Workspace config (.vscode/mcp.json, committed to source control):
Option 3 — User config (settings.json, applies to all workspaces):
Open the Command Palette → Preferences: Open User Settings (JSON) and add:
Cursor
Edit ~/.cursor/mcp.json:
Windsurf
Edit ~/.codeium/windsurf/mcp_config.json:
Zed
Edit ~/.config/zed/settings.json:
Mistral Vibe
Add to ~/.vibe/config.toml:
To pass credentials directly instead of using a config file, use the env field:
MCP tools are exposed as email-mcp_<tool_name> (e.g. email-mcp_list_emails). Restart Vibe after editing the config.
Docker (any MCP client)
Run the server in a container — mount your config directory read-only:
The config mount can stay read-only, but state and cache must be persisted.
The image declares both as volumes, so Docker keeps them in anonymous volumes
if you omit the flags — naming them, as above, is what makes them survive a
docker run --rm. State holds the scheduled-email queue: without it, a restart
drops every email scheduled but not yet sent. Cache holds the local mirror,
which is regenerable, so losing that only costs a re-sync.
For MCP client configuration (e.g. Claude Desktop):
Single-account via environment variables (no config file needed)
Always-on server (detached)
The stdio transport lives only as long as an MCP client keeps it open — which also
means the IMAP watcher (and verification catching) stop with it. email-mcp server
runs the Streamable HTTP server as a background service instead, iMCP-style:
The binding lives in the config file, so a plain server start is deterministic:
Precedence: CLI flags → EMAIL_MCP_HTTP_* env → [settings.server] → defaults —
for email-mcp http, server start, and the launchd login item alike. Edit it
interactively with config edit server (the token renders masked). --insecure
is deliberately flag-only and cannot be persisted.
Start at login (macOS): email-mcp server install writes a launchd login item
(com.email-mcp.server, RunAtLoad + KeepAlive) running email-mcp http with no
flags — the config file is its single source of truth across reboots and crashes.
server status recognizes the launchd mode; server uninstall removes it.
State lives in $XDG_STATE_HOME/email-mcp/daemon.json, logs in server.log next to
it (rotated at 5 MB). stop only ever signals a process whose command line is
verifiably this server (PID-reuse safe). Point HTTP-capable MCP clients at
http://127.0.0.1:8080/mcp; binding non-loopback hosts still requires a token.
Streamable HTTP (networked)
By default the server speaks MCP over stdio, ideal for local desktop clients (see the snippets above). For networked or remote access, run it as a Streamable HTTP server instead:
This serves MCP at http://127.0.0.1:8080/mcp, with a health probe at GET /healthz.
Flags & environment variables
Security
- Token auth — When a token is set, every request must send
Authorization: Bearer <token>. - Non-loopback bind guard — Binding a non-loopback host (e.g.
0.0.0.0) without a token is refused unless--insecureis passed. Use--insecureonly when TLS and authentication are terminated by an upstream reverse proxy. - DNS-rebinding protection — The
Hostheader is validated against an allowlist (loopback names plus the bind host by default). SetEMAIL_MCP_HTTP_ALLOWED_HOSTSto your public domain, or*to disable the check when a proxy already enforces it.
Client configuration
For clients that support the Streamable HTTP transport:
When a token is configured, add an Authorization: Bearer <token> header if your client supports custom headers.
Docker
Requires EMAIL_MCP_HTTP_TOKEN to be set; the image EXPOSEs port 8080.
CLI Commands
Shell completion
Completions cover every command, subcommand, and flag — and complete account
names from your config (email-mcp test <TAB>, account edit <TAB>) and
settings sections (config edit <TAB>) dynamically.
Checking logs
The background daemon logs to $XDG_STATE_HOME/email-mcp/server.log. View it
with a tail/follow/filter viewer — no need to find the file:
email-mcp server logs is an alias with the same options. Color auto-disables
when piped or under NO_COLOR; on a systemd host, journalctl --user -u email-mcp is also available.
Reading and sending mail from the CLI
Beyond running as an MCP server, email-mcp is a usable mail client in its own
right — no MCP client and no coding required. Commands default to your first
configured account (pass --account <name> to pick another), print clean,
colored tables (color auto-disables when piped or under NO_COLOR), and tab
complete (see Shell completion).
Every command accepts --help; the read commands (list, read, search,
mailboxes) accept --json for machine-readable output you can pipe to jq:
Attachment sizes on send/reply are checked against the configured limit before anything leaves your machine (see Storing account secrets for keeping credentials out of plaintext).
Configuration
Located at $XDG_CONFIG_HOME/email-mcp/config.toml (default: ~/.config/email-mcp/config.toml). Validate it with email-mcp config validate (TOML syntax, schema, typo'd keys with did-you-mean, cross-setting consistency; exit 1 on errors — CI-friendly) and edit it interactively with email-mcp config edit [section] — every save validates first and backs up the previous file to config.toml.bak. Note: programmatic saves rewrite the file without TOML comments (the backup keeps them).
Storing account secrets
The password field (and OAuth2 client_secret / refresh_token) accepts an
indirection so credentials need not sit in the file as plaintext:
The config file itself is always written 0600 (owner-only), and so is its
.bak.
macOS Keychain (multi-account): store each account's secret once —
set-secret prompts for the value and stores it; migrate-secret reads the
account's current plaintext password from config.toml, stores it in the
keychain, verifies it, then rewrites the line to password = "keychain:personal".
Either way you end up with password = "keychain:personal". Each account is a separate Keychain
item under the shared email-mcp service, so multiple accounts coexist.
Secrets are read back at startup over the security CLI; only the service and
account names are ever passed as arguments — the secret travels on stdout only.
At rest the secret lives in your login keychain, encrypted and unlocked by
your macOS login (Touch ID at the login level). A running email-mcp daemon
reads it once at startup; it does not prompt for Touch ID on every IMAP
reconnect — per-access biometric prompts are deliberately not used for an
unattended background service. (True per-access Touch ID would require the
data-protection keychain and a native helper.)
OAuth2 (experimental)
Note: OAuth2 support is experimental. Token refresh and provider-specific flows may require additional testing in your environment.
Environment Variables
For single-account setups (overrides config file):
Local Cache
Reads are served from a local SQLite mirror of your mail (plus a
content-addressed store for attachments) under
${XDG_CACHE_HOME:-~/.cache}/email-mcp/. It makes listing, searching, and
re-reading mail fast, and it keeps mail readable when the mail server is
unreachable. It is on by default.
The cache is never authoritative. Every row can be re-fetched from IMAP, so deleting it costs a resync and never loses mail — you can remove the directory at any time, as the XDG cache convention allows.
Seeing and reclaiming what it holds
cache status reports the index size and attachment bytes separately, how many
messages have full text cached, and how long ago each mailbox was reconciled.
check_health exposes the same numbers to an AI client, plus the read hit ratio.
How freshness is decided
Correctness comes first: a stale answer to "any new mail?" is a wrong answer.
Before serving a mailbox from the cache, the server either trusts a reconcile
from the last 10 seconds, or spends one STATUS round trip comparing the
server's UIDVALIDITY/UIDNEXT/HIGHESTMODSEQ/MESSAGES against what the
mirror recorded — the IMAP equivalent of a conditional request. If anything
moved, it resynchronises before answering (bounded; past the bound you get the
cached answer marked stale). If the server is unreachable you get the cached
answer marked offline.
Message bodies and attachments are immutable for a given UIDVALIDITY/UID, so
once stored they are served with no revalidation at all. Writes made through
this server (flagging, moving, deleting) resynchronise the affected mailboxes
immediately, which matters on servers without CONDSTORE where a flag change
is otherwise invisible.
Settings
Past the budget, eviction runs cheapest-to-rebuild-first: attachment files
(least recently read first), then message bodies, then envelopes older than
window_days. Envelopes are kept as long as possible, because they are what
listings and search need.
Coverage, not just freshness. The cache only answers a listing when it
holds every message the server reports for that mailbox. Set window_days to
something other than 0 and the mirror becomes a slice — it then cannot report
a truthful total or know whether more pages exist, so reads fall back to the
live path until it catches up. That is also why envelope eviction clears the
mailbox's sync watermarks: the next sync rebuilds coverage instead of leaving a
permanent, invisible hole.
Data at rest
Cached mail — including message bodies and attachment content — is stored
unencrypted, in a directory and files readable only by your user
(0700/0600). This matches what desktop mail clients do; the recommended
protection is full-disk encryption (FileVault, LUKS). If you would rather not
have bodies and attachments on disk at all, set body_messages = 0, which
keeps the cache metadata-only.
Gmail note: do not add [Gmail]/All Mail to mailboxes. Gmail presents the
same message in every label folder, so mirroring All Mail alongside INBOX
stores the same mail twice.
Email Scheduling
The scheduler enables future email delivery with a layered architecture:
- MCP auto-check — Processes the queue on server startup and every 60 seconds while the MCP server is running
- CLI —
email-mcp scheduler checkfor manual or cron-based processing - OS-level daemon —
email-mcp scheduler installsets up launchd (macOS) or crontab (Linux) to run every minute, independently of the MCP server
Important — the daemon must be installed for reliable delivery. Without it, scheduled emails only fire while an AI client is actively connected. Your machine also needs to be running at the scheduled time; if it's asleep or off, the daemon will process overdue emails on next wake/startup. Failed sends are retried up to 3 times before being marked
failed.
Setting up the daemon
Scheduled emails are stored as JSON files in ~/.local/state/email-mcp/scheduled/ with status-based locking. Each entry tracks attempts (max 3) and the last error, so you can inspect failures with scheduler list.
Real-time Watcher & AI Hooks
The IMAP IDLE watcher monitors configured mailboxes in real-time using persistent IDLE connections (separate from tool connections). When new emails arrive:
- Static rules — Pattern-match on from/to/subject → apply labels, flag, or mark read instantly (no AI)
- AI triage — Remaining emails are analyzed via MCP sampling with a customizable preset prompt
- Notify mode — Falls back to logging if AI triage is disabled
Configure in config.toml:
Presets
Static Rules
Static rules use glob-style patterns (*@github.com) with | as OR separator (*@github.com|*@gitlab.com). All conditions within a match are AND'd. First matching rule wins.
Available actions: labels (string array), flag (boolean), mark_read (boolean), alert (boolean — forces desktop notification).
Alerts
Urgency-based multi-channel notification routing — grab attention for important emails even when you're not looking at the chat. All channels are opt-in and disabled by default.
Supported platforms: macOS (Notification Center via osascript), Linux (notify-send), Windows (PowerShell toast). Zero npm dependencies — uses native OS commands.
Notification setup by platform:
macOS
Desktop notifications use osascript (built-in). The terminal app running the MCP server needs notification permission:
- Open System Settings → Notifications & Focus
- Find your terminal app (Terminal, iTerm2, VS Code, Cursor, etc.)
- Enable Allow Notifications and choose Banners or Alerts
- Ensure Focus / Do Not Disturb is not blocking notifications
Use check_notification_setup to diagnose and test_notification to verify.
Linux
Requires notify-send from libnotify. For sound alerts, paplay is also needed:
Desktop notifications require a running display server (X11/Wayland) — they will not work in headless/SSH sessions.
Windows
Uses PowerShell toast notifications (built-in):
- Open Settings → System → Notifications
- Ensure Notifications is turned on
- Set Focus Assist to allow notifications
- If using Windows Terminal, ensure its notifications are enabled
AI-configurable: The AI can check, test, and configure notifications at runtime:
check_notification_setup— diagnose platform support and show setup instructionstest_notification— send a test notification to verify everything worksconfigure_alerts— enable/disable desktop, sound, threshold, webhook (with optional persist to config file)
Webhook payload:
Static rules can force desktop notifications with alert = true, regardless of urgency threshold:
Features:
- Auto-reconnect — Exponential backoff (1s → 60s) on connection failures
- Batching — Groups arrivals within a configurable delay to reduce AI calls
- Rate limiting — Max 10 sampling calls per minute
- Graceful degradation — Falls back to notify mode if client doesn't support sampling
- Resource subscriptions — Pushes
notifications/resources/updatedfor unread counts
Verification codes (instant OTP catch)
When a mail carrying a verification code (OTP/2FA) or sign-in magic link arrives, email-mcp copies it to your clipboard within ~1–2 seconds and shows a notification — “✅ Code 482913 from GitHub — Copied to clipboard, clears in 60s”. Press ⌘V / Ctrl+V, done.
Detection is scoring-based (English + German), not a bare digit regex: keyword proximity
(verification, Bestätigungscode, expires, …) minus negative context (order numbers,
invoices, tracking, Zoom passcodes, phone numbers, prices, dates). A miss beats a wrong
code on your clipboard.
Ask-first mode: with confirm_copy = true, a native macOS dialog ("Code 482913 from
GitHub — Copy to clipboard?") appears before anything touches your clipboard. Sign-in
links get a three-button dialog by default (link_action = "open"): Open launches
the link in your default browser, Copy puts it on the clipboard, Cancel does
nothing — opening is always confirmed, since auto-launching a browser from mail content
would be a phishing hazard. Set link_action = "copy" for the silent clipboard behavior.
Dialogs are macOS-only (same mechanism as the calendar confirmation); elsewhere these
modes degrade to notification-only.
Clipboard hygiene (macOS): codes are written via a JXA osascript with the
org.nspasteboard.ConcealedType marker — the same convention 1Password/Bitwarden use — so
well-behaved clipboard managers (Maccy, Paste, …) never record them. The auto-clear is
conditional: the clipboard is only cleared if it still holds the caught value, so anything
you copied in the meantime is never stomped. Linux uses wl-copy/xclip, Windows uses
PowerShell Set-Clipboard (no concealment convention exists there). Zero npm dependencies.
For agents: get_verification_code fetches the newest code on demand — during an
automated signup, call it with wait_seconds = 30 and it returns the code seconds after
the mail lands (event-driven with the watcher, 5 s polling without). If nothing arrives in
time, it returns found: false with a hint — just call it again.
Security notes: the clipboard is shared OS state — any app can read it while the code
is there (that window is bounded by clear_after_seconds). The code itself is never
written to server logs or the audit log; it does appear in get_verification_code results,
which is the point of that tool. Kill switches: enabled = false (feature off) or
auto_copy = false (notification only). Environment overrides: MCP_EMAIL_VERIFICATION_*
(_ENABLED, _AUTO_COPY, _CONFIRM_COPY, _NOTIFY, _COPY_LINKS, _LINK_ACTION,
_CLEAR_AFTER_SECONDS, _MAX_AGE_MINUTES, _ACCOUNTS, _SENDER_ALLOWLIST,
_SENDER_DENYLIST).
Use check_clipboard_setup to diagnose the pipeline (add test_write = true for a
harmless copy → read-back → clear round-trip).
API
Tools (52)
Structured output:
list_emails,search_emails,get_email_status,list_mailboxes, andget_verification_codealso return machine-readable results (outputSchema+structuredContent) alongside the human-readable text, for clients that consume typed tool output.
Email bodies: HTML and other formats
Nearly all real mail is HTML — in one sampled mailbox, 165 of 169 messages were
single-part text/html — so the read tools convert it rather than handing back
markup.
get_email, get_emails, and get_thread take a format:
Bodies are capped by default — 10 000 characters for get_email, 5 000 per
message for get_emails and get_thread — and a hint reports how much was
left out. Pass maxLength: 0 for no cap. Each side of the body (text, HTML) is
read up to 512 KB, shared across its parts.
Other formats behave as follows:
multipart/alternative— both halves are fetched, sobodyTextandbodyHtmlare both available. A plain part too small to hold the same content as its HTML sibling is treated as a "view this in an HTML reader" placeholder and skipped.multipart/mixedwith several text parts — concatenated in order, so a note split either side of an inline image (Apple Mail) or a per-message digest section is not truncated to its first part.text/plain; format=flowed(RFC 3676) — soft line wraps are undone, so paragraphs read as paragraphs rather than hard-wrapped at 72 columns;DelSpand space-stuffing are honoured.- Inline (
cid:) images — listed as attachments withpartId,contentId, andinline, and downloadable viadownload_attachment'spartId. To embed one when sending, pass{path, cid, contentType}inattachmentsand reference it as<img src="cid:…">. - Bounces (
multipart/report) — the machine-readablemessage/delivery-statuspart is surfaced separately from the body. - Calendar invites — handled by
extract_calendar/add_to_calendar, honouring the part's declared charset. - Encrypted mail (S/MIME, PGP/MIME) — not decrypted; the body says so plainly instead of appearing empty.
- Attached messages (
message/rfc822) — never mistaken for the body, but used as the body when the message carries no other text (forward-as-attachment, digests).
Attachment download directory. download_attachment normally returns the
file base64-encoded (≤5 MB). Set [settings.attachment_download] dir (or
MCP_EMAIL_ATTACHMENT_DOWNLOAD_DIR) to a directory and pass
saveToDownloadDir: true to instead write the file there and get back its
path — useful for larger files, or when the caller just wants the attachment
on disk rather than inlined into the conversation. The option is unavailable
(the call fails) until dir is set — there is no default location. Only
allowed_extensions are written (default: common document/image types; see
the config example above); max_bytes caps the size, independent of the
5 MB base64 cap. Pass saveAs to choose the filename written there (a plain
basename — no path separators); otherwise the attachment's own filename is
sanitized and used. Running in Docker, point dir at a mounted volume shared
with whatever reads the files back, e.g. in docker-compose.yml:
Sent-folder copies. SMTP delivers mail; it does not file it. [settings.send] save_to_sent defaults to false; turn it on for an IMAP host that does not
capture sends itself. Gmail does capture sends server-side, so an account
whose IMAP server advertises the X-GM-EXT-1 capability is skipped
automatically even with the setting on — filing a copy there would give you
two of everything. Set the account's own save_to_sent to force the decision
either way (true files anyway, false never files, regardless of the
global setting or the Gmail guess).
The copy carries the same Message-ID the server accepted, is flagged
\Seen, and lands in the folder the server marks \Sent (or a folder named
Sent, created if absent). On a mailbox that carries several sent-shaped
folders — a leftover Sent beside the one actually in use — that guess can
land on an empty one; set the account's sent_mailbox to the full path
(as list_mailboxes reports it) to settle it. The copy omits Bcc, which the
MIME composer strips unconditionally.
A failure to file never fails the send — the mail has already left, and
saying otherwise would invite a duplicate send — but send_draft keeps the
draft in that case rather than deleting the only remaining copy of the
message. send_email, reply_email, forward_email and send_draft all
report the outcome in their result's sentCopy field: {kind: "filed", path},
{kind: "skipped"} (setting off, or Gmail's own capture), or
{kind: "failed", error}.
Outbound HTML (html: true) is sent as multipart/alternative with a
generated plain-text alternative. Forwards quote the original as converted
text; pass html: true to forward_email to also carry the original HTML.
Read (14)
Bulk-mail classification
list_emails, search_emails, get_email, get_emails and get_thread mark
list and machine-generated mail, so an inbox can be triaged without reading
bodies:
A newsletter also reports its unsubscribe URI when the sender offers one, and
flags 1-click when RFC 8058 one-click unsubscribe is supported. The headers
are requested as part of the listing fetch, so classifying a whole page costs no
extra round trip.
Classification is header-derived and therefore deterministic — no model call and no heuristics on subject text. A sender that omits the headers is reported as personal mail rather than guessed at. These are sender-asserted headers, not verified ones — treat the marker as a signal to weigh, not a fact to defer to.
Body previews
list_emails and search_emails accept preview: true to include roughly 200
characters of each message body. It is off by default: it fetches 1500 extra
bytes per message and lengthens the tool output, which is a cost the caller
should choose rather than inherit.
The preview is decoded from one body part rather than from message source —
IMAP section 1, or 1.1 when section 1 is itself a multipart. Because the fetch
stops at a byte count rather than at an encoding boundary, decoding tolerates
input cut mid-stream: base64 is truncated to a whole group, a half-written
quoted-printable escape is dropped, and the replacement character left by a
severed UTF-8 sequence is trimmed. Charsets beyond UTF-8 are handled — real mail
still ships iso-8859-1.
Markup is stripped whether or not the sender declared it, since bulk senders
routinely put HTML and stylesheets in a part labelled text/plain. Entities and
zero-width preheader padding are decoded, and a preview that reduces to markup
residue is omitted: no preview beats a misleading one.
Write (9)
Manage (7)
Labels (5)
Watcher & Alerts (6)
Verification (3)
Calendar & Reminders (8)
Prompts (7)
Resources (6)
Provider Auto-Detection
Architecture
Roadmap
Ideas raised but deliberately not built yet, kept here so they aren't lost or quietly re-proposed:
- AgentMail as an alternative provider. AgentMail
offers API-key-only, programmatic
@agentmail.toinboxes — no IMAP/SMTP host/port/TLS/credential setup, useful for spinning up throwaway agent-owned addresses. It would be additive (a second provider alongside real IMAP/SMTP accounts, not a replacement), but is a product/architecture decision — a new vendor dependency and tool surface — rather than a bug fix or gap-fill, so it's parked here rather than auto-built. Revisit if there's real demand for agent-provisioned inboxes rather than access to existing mailboxes.
Maintainers
Release prerequisites
release.yml checks these before publishing anything, so a missing one is a
fast red run rather than a half-published release:
The Homebrew cask ships the unsigned Bun binary, so its postflight clears
the macOS quarantine bit — macOS only, since Linux has no xattr(1) and the
cask DSL's system_command raises on a non-zero exit. brew uninstall --zap
trashes the config, state, cache and data directories plus the two launch
agents.
Contributing
PRs accepted. Please conform to the standard-readme specification when editing this README.
Testing
The integration suite runs each tool against a throwaway GreenMail server
(spun up via Testcontainers). Attachment coverage
(email-attachments.integration.test.ts) drives the real MCP tool layer and
locks in the size-awareness contract: every send reports each file's size and
the raw≈base64 total, the cap is enforced on the encoded total (what the
wire carries), an over-cap send fails closed (nothing is delivered), and
forwards carry the original attachments unless includeAttachments: false.
The effective cap is resolved per account: an explicit per-account
max_attachment_mb wins outright; otherwise the stricter of the global
[settings.send] cap and the provider's documented limit applies (Gmail,
Yahoo, and Proton 25 MB; Outlook.com, iCloud, and GMX 20 MB; Fastmail 50 MB).
pnpm smoke drives all tools over stdio the way a client does, which reaches
what GreenMail cannot: provider quirks, real-world MIME, and the macOS
Calendar bridges. It needs a working account, so it is not part of CI. Writes
stay inside a scratch folder and a draft it creates itself; it does not touch
Calendar, Reminders, notifications, or reply_email, which would send mail to
a real correspondent. Pass E2E_ACCOUNT=<name> to choose an account, otherwise
it uses the first one configured.
License
来源:README.md,提交 7d31cd5
工具
0版本历史
3- v0.6.0最新Oct 10, 2026
- v0.5.1Sep 26, 2026
- v0.2.3Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分