Secure IMAP/SMTP/EWS/Graph API MCP server in Rust — Microsoft 365, Hotmail, Gmail, Zoho, OAuth2, multi-account
mail-mcp
以下摘录自该仓库的 README(片段) · 在 GitHub 读完整 README →
Production-ready email MCP server for AI agents
IMAP + SMTP + EWS + Microsoft Graph API — built in Rust
---
Most email MCP servers only do IMAP reads. This one does **everything**: read, search, send, reply, forward, bulk operations, Microsoft Graph API, and Exchange Web Services — with real OAuth2, multi-account, and multi-provider support. Written in Rust for speed and safety.
What's New in v0.5.0
- **New: draft tools** (draft_create, draft_update, draft_send,
draft_delete, draft_list) closing
#3 and
#17. An agent can
save a message in the account's own Drafts folder, revise it, and send it
later, so a person can review it in their mail client first. The same five
tools work on every backend: IMAP + SMTP, Exchange Web Services and
Microsoft Graph, picked per account (EWS config, else Graph config, else
IMAP). list_all_accounts reports the backend as drafts_with.
- **Separate gate: MAIL_DRAFTS_ENABLED** (default false). It is
independent of MAIL_IMAP_WRITE_ENABLED: every operation on an existing
draft_id first checks that the target really is a draft (IMAP Drafts
folder, EWS IsDraft, Graph isDraft), so enabling drafts never grants
move or delete on other mail. draft_send also requires
MAIL_SMTP_WRITE_ENABLED.
- **Graph accounts need the Mail.ReadWrite scope** for drafts; see
account setup. The EWS attachment flow
(CreateItem with SaveOnly, then CreateAttachment) follows the approach
proposed by @verdelyi in
#14.
- **Fix: SMTP messages now carry a Message-ID on the sender's domain**
(#7). Before, lettre
sent no Message-ID of its own, so the id returned by the send tools was
empty and the Sent copy had none.
- Verified live on IMAP (Zoho) and Microsoft Graph; the EWS draft path is
covered by unit tests.
What's New in v0.4.17
- **New: imap_search_all_mailboxes** by
@tdabasinskas in
#35. Runs one search
in every selectable mailbox of an account and returns the newest matches,
each labelled with its mailbox. Built for providers without an "All Mail"
folder (iCloud), where one conversation is spread over INBOX, Sent Messages
and project folders. The work is spread over MAIL_IMAP_SEARCH_CONCURRENCY
connections (default 4, clamped to 1..=8); a mailbox that fails is
reported and does not abort the search. Scope it with include_mailboxes /
exclude_mailboxes.
- **Thread search by Message-ID** by
@tdabasinskas in
#34.
imap_search_messages takes a new thread_message_id criterion that
matches a message and every message whose In-Reply-To or References
carries it, so an agent can pull a whole conversation in one search.
What's New in v0.4.16
- **imap_list_mailboxes cap is now configurable and visible** by
@tdabasinskas in
#33. The tool used to
silently drop everything past 200 mailboxes — on accounts with more folders
(e.g. 217 on iCloud), folders like Sent Messages simply never appeared.
The cap is now set with MAIL_IMAP_MAX_MAILBOXES (default 200, clamped to
1..=10000), and the response carries two additive fields, total and
truncated, so clients can always tell a capped list from a complete one.
Nothing changes unless the variable is set.
What's New in v0.4.15
- **New: opt-in streamable HTTP transport** by
@tdabasinskas in
#32. Set
MAIL_MCP_TRANSPORT=http to serve MCP streamable HTTP (stateless) instead
of stdio — useful for running the server on another machine behind an MCP
gateway. Binds to 127.0.0.1:8000 at /mcp by default, configurable via
MAIL_MCP_HTTP_HOST / MAIL_MCP_HTTP_PORT / MAIL_MCP_HTTP_PATH, with
graceful shutdown on SIGINT/SIGTERM. **The endpoint has no built-in
authentication** — keep it on loopback or behind an authenticating gateway;
see docs/advanced-configuration.md#remote-http-transport. stdio remains
the default: nothing changes unless the variable is set.
What's New in v0.4.14
Community release — both changes came from external contributors. Thank you!
- **New: MAIL_ATTACHMENT_UPLOAD_DIR — confine outbound file_path
attachments** by @mjones-PL in
#31, closing
#11. Without a
restriction, send tools would read any file the server process can access —
a prompt-injected model could exfiltrate SSH keys or .env files as
attachments. Set this variable to a directory and every file_path is
canonicalized (.. and symlinks resolved) and must land inside it; missing
and out-of-scope files return the same error so the check cannot probe for
file existence. Opt-in: when unset, behavior is unchanged. See
docs/security.md#outbound-attachment-scope.
- **Fixed: FROM_EMAIL validation no longer rejects dotless internal hosts**
by @arwack in