anymail-mcp
Connects any IMAP/SMTP mailbox to AI agents via MCP, enabling email read, search, send, reply, and management through natural language.
README
anymail-mcp
Connect ANY mailbox to ANY AI agent. Expose Gmail, Outlook, Apple Mail (iCloud), Fastmail, ProtonMail, Yahoo, and every self-hosted server (Stalwart, Dovecot, Postfix, Mailcow) as Model Context Protocol tools, so any MCP-compatible agent (Claude Desktop, Hermes, your own scripts) can read, search, send, reply to, and manage email.
9 tools · 82 unit tests · HTTP/MCP daemon (no stdio zombies) · MIT
┌──────────────────┐ HTTP + SSE ┌──────────────────┐ IMAP ┌────────────┐
│ MCP client │ ────────────────► │ anymail-mcp │ ───────►│ Mail │
│ (Claude, │ │ (HTTP daemon) │ │ server │
│ Hermes, etc.) │ ◄──────────────── │ :3143/mcp │ SMTP │ (any) │
└──────────────────┘ Server-Sent Eve └──────────────────┘ ───────►└────────────┘
Why httpStream (not stdio)?
This server defaults to httpStream — a persistent HTTP daemon that speaks
MCP over Server-Sent Events. Unlike stdio (one process per client session),
httpStream is:
- A single daemon serving multiple clients — no zombie processes piling up
- Always warm — IMAP/SMTP connections stay alive between requests
- Network-accessible — any machine on your LAN (or via reverse proxy) can connect to the same instance
- systemd-friendly — runs as a managed service, restarts on crash
Use stdio only for single-user desktop apps (Claude Desktop local integration).
📦 Install
Option A — npm (fastest)
npm install -g anymail-mcp
Then create a config file and start:
# Create config
cat > ~/.anymail-mcp.env << 'EOF'
IMAP_HOST=imap.gmail.com
IMAP_USER=you@gmail.com
IMAP_PASS=your-app-password
SMTP_HOST=smtp.gmail.com
SMTP_USER=you@gmail.com
SMTP_PASS=your-app-password
EOF
# Start the daemon (reads .env from cwd or ~/.anymail-mcp.env)
anymail-mcp
# → [INFO] HTTP Stream listening on http://0.0.0.0:3143/mcp
Option B — From source
git clone https://github.com/DeamonDev888/anymail-mcp.git
cd anymail-mcp
npm install
npm run build # TypeScript → dist/
cp .env.example .env
# Edit .env with your IMAP/SMTP credentials
npm start
# → [INFO] HTTP Stream listening on http://0.0.0.0:3143/mcp
Option C — systemd daemon (production)
# Clone + build
git clone https://github.com/DeamonDev888/anymail-mcp.git /opt/anymail-mcp
cd /opt/anymail-mcp
npm install && npm run build
# Config
cp .env.example .env
nano .env # fill in credentials
# Create systemd service
cat > /etc/systemd/system/anymail-mcp.service << 'EOF'
[Unit]
Description=anymail-mcp — IMAP/SMTP MCP Server
After=network.target
[Service]
Type=simple
User=mail
WorkingDirectory=/opt/anymail-mcp
EnvironmentFile=/opt/anymail-mcp/.env
ExecStart=/usr/bin/node /opt/anymail-mcp/dist/index.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now anymail-mcp
systemctl status anymail-mcp
The anymail-mcp bin helper
When installed via npm install -g, the package ships a CLI helper
(dist/index.js with #!/usr/bin/env node shebang) registered as:
$ anymail-mcp
It loads .env from the current working directory (or from
~/.anymail-mcp.env), validates config, and starts the HTTP daemon on
:3143/mcp. Use FASTMCP_TRANSPORT=stdio env var to switch to stdio mode
for desktop integrations.
🔌 Connect your MCP client
Once the daemon is running on http://localhost:3143/mcp, add it to any
MCP-compatible client config:
Claude Desktop / Claude Code
{
"mcpServers": {
"mail": {
"url": "http://localhost:3143/mcp"
}
}
}
Hermes Agent
In config.yaml:
mcp:
mail:
url: "http://localhost:3143/mcp"
Remote server
Replace localhost with your server hostname:
{
"mcpServers": {
"mail": {
"url": "http://mail.myserver.com:3143/mcp"
}
}
}
⚙️ Configuration
All configuration is via environment variables (.env file or shell exports).
Required
| Variable | Description |
|---|---|
IMAP_HOST |
IMAP server hostname (e.g. imap.gmail.com) |
IMAP_USER |
IMAP username (often your full email address) |
IMAP_PASS |
IMAP password or app password |
SMTP_HOST |
SMTP server hostname (often same as IMAP host) |
SMTP_USER |
SMTP username |
SMTP_PASS |
SMTP password or app password |
Optional
| Variable | Default | Description |
|---|---|---|
IMAP_PORT |
993 |
IMAP port (993 = SSL, 143 = STARTTLS) |
IMAP_SECURE |
true |
Use implicit TLS |
IMAP_REJECT_UNAUTHORIZED |
false |
Reject invalid TLS certs (set true in prod) |
SMTP_PORT |
465 |
SMTP port (465 = SSL, 587 = STARTTLS) |
SMTP_SECURE |
true |
Use implicit TLS |
SMTP_REJECT_UNAUTHORIZED |
false |
Reject invalid TLS certs |
SMTP_FROM |
SMTP_USER |
Override "From" address (aliases) |
FASTMCP_TRANSPORT |
httpStream |
httpStream or stdio |
FASTMCP_PORT |
3143 |
HTTP port (httpStream mode) |
FASTMCP_HOST |
0.0.0.0 |
Bind address (127.0.0.1 = local only) |
LOG_LEVEL |
info |
fatal error warn info debug trace |
LOG_DIR |
./logs |
Log file directory |
Security (optional, opt-in)
| Variable | Default | Description |
|---|---|---|
AUTH_TOKEN |
(none) | Bearer token for HTTP transport auth |
ALLOWED_DOMAINS |
(all) | Comma-separated recipient domain allowlist |
REDACT_LOGS |
true |
Mask emails + passwords in logs |
Example .env
IMAP_HOST=imap.gmail.com
IMAP_USER=you@gmail.com
IMAP_PASS=abcd efgh ijkl mnop
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.gmail.com
SMTP_USER=you@gmail.com
SMTP_PASS=abcd efgh ijkl mnop
SMTP_PORT=465
SMTP_SECURE=true
FASTMCP_TRANSPORT=httpStream
FASTMCP_PORT=3143
FASTMCP_HOST=0.0.0.0
LOG_LEVEL=info
🧰 Tools (9)
| Tool | Description |
|---|---|
server_info |
Server details + inbox message counts |
list_mailboxes |
List all mailboxes (INBOX, Sent, Drafts, Junk...) |
list_emails |
List emails with subject, from, date, preview |
read_email |
Read full email body by UID |
search_emails |
Search by keyword (subject/from/to/body) |
send_email |
Send plain-text or HTML email via SMTP |
reply_email |
Reply to a thread (In-Reply-To + References) |
mark_read |
Toggle \Seen flag (read/unread) |
delete_email |
Delete email (flag + expunge) |
<details> <summary>📋 Detailed tool reference</summary>
list_emails
| Param | Type | Default | Description |
|---|---|---|---|
mailbox |
string | INBOX |
Mailbox name |
limit |
number | 20 |
Max results (1–500) |
unread_only |
boolean | false |
Only unread |
Returns: [{ uid, subject, from, to, date, flags, preview }]
read_email
| Param | Type | Default | Description |
|---|---|---|---|
uid |
number | (required) | Email UID from list_emails |
mailbox |
string | INBOX |
Mailbox name |
full |
boolean | false |
false = preview (first 200 chars), true = full body |
Returns: { uid, subject, from, to, date, flags, preview, body, truncated? }
search_emails
| Param | Type | Default | Description |
|---|---|---|---|
query |
string | (required) | Keyword |
mailbox |
string | INBOX |
Mailbox |
limit |
number | 20 |
Max results |
send_email
| Param | Type | Default | Description |
|---|---|---|---|
to |
string | (required) | Recipient |
subject |
string | (required) | Subject line |
body |
string | (required) | Email body (plain text or HTML) |
is_html |
boolean | false |
Treat body as HTML |
preview |
boolean | false |
Validate payload without sending |
Returns: { status: "sent", to, subject, messageId, sizeBytes }
reply_email
| Param | Type | Default | Description |
|---|---|---|---|
uid |
number | (required) | UID of email to reply to |
body |
string | (required) | Reply body (plain text) |
mailbox |
string | INBOX |
Mailbox containing original |
Reads the original email, extracts Message-ID + From + Subject, then sends a
reply with proper threading headers (In-Reply-To, References) and Re:
prefix.
Returns: { status: "sent", to, subject, messageId, inReplyTo }
mark_read / delete_email
| Param | Type | Default | Description |
|---|---|---|---|
uid |
number | (required) | Email UID |
mailbox |
string | INBOX |
Mailbox |
read |
boolean | true |
(mark_read only) true=read, false=unread |
</details>
📧 Provider quick-start
<details> <summary><b>Gmail</b></summary>
- Enable 2FA → Google Account Security
- Create an app password
- Use the app password as
IMAP_PASS/SMTP_PASS
IMAP_HOST=imap.gmail.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_SECURE=true
</details>
<details> <summary><b>Outlook / Microsoft 365 / Hotmail</b></summary>
- Enable 2FA on your Microsoft account
- Create an app password via Microsoft account security
IMAP_HOST=outlook.office365.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_SECURE=false
</details>
<details> <summary><b>Apple iCloud / me.com / mac.com</b></summary>
- Enable 2FA on your Apple Account
- Generate an app-specific password at appleid.apple.com → Sign-In and Security → App-Specific Passwords
IMAP_HOST=imap.mail.me.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.mail.me.com
SMTP_PORT=587
SMTP_SECURE=false
</details>
<details> <summary><b>Fastmail</b></summary>
IMAP_HOST=imap.fastmail.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.fastmail.com
SMTP_PORT=465
SMTP_SECURE=true
</details>
<details> <summary><b>ProtonMail Bridge</b></summary>
Requires ProtonMail Bridge running locally:
IMAP_HOST=127.0.0.1
IMAP_PORT=1143
IMAP_SECURE=false
SMTP_HOST=127.0.0.1
SMTP_PORT=1025
SMTP_SECURE=false
IMAP_USER=your-bridge-username
IMAP_PASS=your-bridge-password
</details>
<details> <summary><b>Yahoo / AOL</b></summary>
Generate an app password in Yahoo Account Security.
IMAP_HOST=imap.mail.yahoo.com
SMTP_HOST=smtp.mail.yahoo.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_PORT=465
SMTP_SECURE=true
</details>
<details> <summary><b>Zoho Mail</b></summary>
IMAP_HOST=imap.zoho.com
IMAP_PORT=993
IMAP_SECURE=true
SMTP_HOST=smtp.zoho.com
SMTP_PORT=465
SMTP_SECURE=true
</details>
<details> <summary><b>Self-hosted (Stalwart, Dovecot, Postfix, Mailcow)</b></summary>
For self-signed certificates:
IMAP_REJECT_UNAUTHORIZED=false
SMTP_REJECT_UNAUTHORIZED=false
For valid Let's Encrypt certs in production:
IMAP_REJECT_UNAUTHORIZED=true
SMTP_REJECT_UNAUTHORIZED=true
</details>
🛠️ Development
npm run build # TypeScript → dist/
npm run dev # Watch mode (tsx watch)
npm run lint # ESLint
npm test # Unit tests (vitest)
npm run test:watch # Tests in watch mode
npm run format # Prettier
Project layout
src/
index.ts # Entry point — FastMCP server setup
config.ts # Env loading + Zod validation
logger.ts # Pino logger
mail-service.ts # IMAP/SMTP operations (ImapFlow + nodemailer)
tools.ts # 9 MCP tool definitions (Zod schemas)
security.ts # Input sanitization + allowlist enforcement
tests/
*.test.ts # 82 unit tests
dist/ # Compiled output (gitignored)
Adding a new tool
- Add a method to
MailServiceinsrc/mail-service.ts - Register the tool in
registerMailTools()insrc/tools.ts - Add tests in
tests/
🔒 Security
- No secrets in code — all credentials come from environment variables
- Use app passwords for Gmail/Outlook/Yahoo (never your account password)
- Set
IMAP_REJECT_UNAUTHORIZED=truein production with valid certs - Bind
FASTMCP_HOST=127.0.0.1if the client runs on the same host - For remote access, use a reverse proxy (nginx) with TLS termination
AUTH_TOKENenables Bearer authentication for HTTP transportALLOWED_DOMAINSrestricts who can receive emails viasend_emailREDACT_LOGS=truemasks emails + passwords in structured logs
📜 License
MIT — see LICENSE.
🤝 Contributing
Issues and PRs welcome at github.com/DeamonDev888/anymail-mcp.
Please run npm run lint && npm test before submitting.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。