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.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.