Mail MCP
Provides email management for AOL Mail accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for Gmail and Google Workspace accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for GMX Mail accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for iCloud Mail accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for Mail.ru accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for Migadu mailboxes, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Provides email management for Proton Mail accounts via Proton Bridge, including reading, searching, sending, replying, and organizing messages through IMAP/SMTP.
Provides email management for Zoho Mail accounts, including reading, searching, sending, replying, and organizing messages via IMAP/SMTP.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Mail MCPCheck my inbox for unread emails and summarize them."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Mail MCP
An MCP server for any IMAP mailbox — Gmail, Outlook, iCloud, Fastmail, Yandex, your company's own server. Not tied to a provider, an account or a project: it is configured with the host, the address and the password, and that is the whole binding.
20 tools covering reading, searching, threading, sending, replying, forwarding, drafts, flags, folders and attachments.
The headline feature: the server reads attachments. A screenshot mailed to you is downloaded and handed to the model as an image — not as a filename it cannot open.
Two ways to run it
Mode | Transport | Configuration comes from | Use it when |
Local | stdio | environment variables | the default for mail — credentials never leave the machine |
Hosted | Streamable HTTP on | request headers, per call | clients should connect to a URL with nothing installed |
Mail is not a scoped API token: the password usually opens the whole mailbox, and often the account behind it. Running locally is therefore the recommended mode, and the hosted endpoint exists for the cases where that is not practical — see Hosted mode for what that choice actually costs.
git clone git@github.com:amalychev/mail-mcp.git
cd mail-mcp
npm install
npm run buildRequires Node.js 20 or newer.
Connecting from Claude Code
claude mcp add mail \
--env MAIL_USER=you@fastmail.com \
--env MAIL_PASSWORD=your-app-password \
-- node /absolute/path/mail-mcp/dist/index.jsThat is the whole setup for a known provider: the IMAP and SMTP hosts are derived from the
address. Ask for mail_whoami to confirm — it logs in to both servers and reports what it
found.
Or drop a .mcp.json into the root of your working repository:
{
"mcpServers": {
"mail": {
"command": "node",
"args": ["/absolute/path/mail-mcp/dist/index.js"],
"env": {
"MAIL_USER": "you@example.com",
"MAIL_PASSWORD": "${MAIL_PASSWORD}",
"IMAP_HOST": "imap.example.com",
"SMTP_HOST": "smtp.example.com"
}
}
}
}The same block works in Claude Desktop (claude_desktop_config.json) and Cursor
(.cursor/mcp.json). Write "${MAIL_PASSWORD}" rather than the password itself — Claude Code
and Cursor substitute environment variables, so the file stays shareable and the secret stays
in your shell.
Several mailboxes at once — several entries with different names:
{
"mcpServers": {
"mail-work": { "command": "node", "args": ["…/dist/index.js"], "env": { "MAIL_USER": "me@company.com", "MAIL_PASSWORD": "…" } },
"mail-personal": { "command": "node", "args": ["…/dist/index.js"], "env": { "MAIL_USER": "me@fastmail.com", "MAIL_PASSWORD": "…" } }
}
}Two things worth knowing when a change appears to do nothing:
In Claude Code an entry added to the local scope (kept in
~/.claude.json) takes precedence over the project's.mcp.json.claude mcp listshows what is actually in use, andclaude mcp remove <name> -s localdrops a stale one.Client configuration is read at startup, so restart the app after editing the file.
Related MCP server: io.github.p-w-4-z/inbox-mcp
The password
Nearly every provider refuses your account password over IMAP and wants an app-specific password — a separate value you generate once, use here, and can revoke without touching the account itself.
Provider | Where to get it |
Gmail / Workspace | Turn on 2-Step Verification, then App passwords. Workspace accounts also need IMAP enabled by an administrator |
iCloud | appleid.apple.com → Sign-In and Security → App-Specific Passwords. The login is often the part of the address before |
Yahoo / AOL | Account security → Generate app password |
Fastmail | Settings → Privacy & Security → App passwords |
Yandex / Mail.ru | Security → app passwords, and IMAP switched on under mail-client settings |
Zoho | Security → App passwords, plus IMAP access in Mail Settings |
Outlook.com / Microsoft 365 | Usually OAuth only — see below |
Proton | Install Proton Bridge and use the credentials it shows, not your Proton password |
Microsoft has switched personal accounts and most tenants to OAuth, so a password often
fails outright. Supply an access token as MAIL_PASSWORD together with MAIL_AUTH_TYPE=oauth2;
the same setting works for Gmail's OAuth if you prefer it to an app password.
When authentication fails, the error names your provider and says what it wants — the message is not a generic "login failed".
Configuration
In stdio mode everything is configured through environment variables.
Variable | Required | Default | Description |
| yes | — | The address (or login name) you sign in with |
| yes | — | App-specific password, or an OAuth token with |
| no | detected | Preset that fills in all four host settings |
| no | from preset | Incoming server. A host pasted with |
| no | from port |
|
| no | from preset | Outgoing server. Omit entirely for a read-only mailbox |
| no | the IMAP ones | When the outgoing server wants separate credentials |
| no |
| The From header. Required when the login is not an address |
| no | password |
|
| no |
| Folder used when a tool does not name one |
| no |
|
|
| no | — | Comma-separated addresses or |
| no | — | Comma-separated folders; everything else is out of scope |
| no |
|
|
| no |
|
|
| no |
| Per-connection timeout |
| no |
| Largest attachment read or sent |
| no |
| Bodies longer than this are truncated |
| no |
|
|
MAIL_ADDRESS, MAIL_PASS, IMAP_USER, IMAP_PASSWORD, MAIL_IMAP_HOST and
MAIL_SMTP_HOST are accepted as aliases.
Providers with a preset
gmail, outlook, yahoo, icloud, fastmail, zoho, yandex, mailru, gmx, aol,
migadu, mailbox, proton — each fills in the IMAP and SMTP host, port and transport.
Aliases such as google, hotmail, office365 and protonmail resolve to the right one, and
an address ending in a domain the preset owns selects it with no configuration at all.
Anything else is a normal IMAP server: give the two hosts and it works.
What the tools do
Messages are addressed by UID within a folder. A UID is only meaningful together with the folder it came from, and a message that moves gets a new one — every tool that returns messages returns the folder alongside them.
Folders accept aliases: inbox, sent, drafts, trash, junk, archive resolve
through the server's own special-use flags, so they work whether the account calls it Sent,
[Gmail]/Sent Mail or Отправленные.
Reading
Tool | Description |
| Newest messages in a folder, with an optional preview of each |
| Sender, recipient, subject, body, date range, read state, size, arbitrary headers |
| One message: headers, readable body, attachment list |
| The whole conversation, oldest first, including your own replies from Sent |
| The raw source — Received chains, SPF/DKIM, list headers |
mail_read_message fetches only the body part, so a message carrying a 20 MB attachment still
costs a few kilobytes to read. HTML-only mail is flattened to prose with the links kept.
Reading never marks anything as read unless you pass mark_read: true.
Attachments
Tool | Description |
| What is attached, with the part ids needed to fetch it |
| Downloads one: images come back as images, text as text, the rest as a base64 resource |
Writing
Tool | Description |
| A new message, with attachments from disk or from base64 |
| Threads properly: In-Reply-To and References are carried over, |
| With the usual header block and, unless disabled, the original attachments |
| Writes into Drafts without sending — for text a person should review first |
Every sent message is filed in the Sent folder, and the copy is the exact bytes that were sent rather than a re-composed lookalike. The From address comes from the deployment and cannot be overridden by a tool argument.
Organising
Tool | Description |
| Read/unread, flagged, answered, custom keywords, several messages at once |
| Marks everything a search matches, with a ceiling so a broad query cannot run away |
| File mail into folders |
| Moves to Trash; |
| The folder tree, with counts on request |
| Create, rename, delete, subscribe, unsubscribe |
| Logs in to both servers and reports account, quota and restrictions |
Keeping it inside bounds
An assistant with a mailbox password can, in principle, read everything and write to anyone. Three independent limits narrow that, and they stack:
Read-only. MAIL_READ_ONLY=true refuses every tool that sends, moves, flags or deletes.
Reading still works completely.
A recipient allowlist. MAIL_ALLOWED_RECIPIENTS=@yourcompany.com,partner@client.com checks
every recipient — To, Cc and Bcc together — before anything reaches the SMTP server. This is
the one worth setting even when everything else is open: it turns "the assistant could email
anyone" into "the assistant could email these people".
A folder allowlist. MAIL_ALLOWED_FOLDERS=INBOX,INBOX/Clients puts every other folder out
of reach, for reading as well as writing. A listed folder covers its subfolders. The
"no such folder" error is filtered to the allowed set, so it cannot be used to map the account.
Beyond that: deleting is a move to Trash unless permanent: true and confirm: true are both
given, deleting a folder needs confirm: true, and an app-specific password can be revoked in
the provider's interface without touching the account.
Hosted mode
Start the HTTP transport with MCP_TRANSPORT=http (or --http). It serves:
Route | Purpose |
| the landing page ( |
| the MCP endpoint, stateless — one server instance per request |
| liveness probe |
| generated per request from the |
| static files from |
Every request carries its own credentials, so one deployment serves many mailboxes without holding state:
Header | Maps to |
|
|
|
|
| the incoming server |
| the outgoing server |
| the From header |
|
|
| the guard rails above |
|
|
TLS verification, timeouts and the size caps are deliberately not header-controlled: they are process-wide and belong to whoever runs the deployment. Attaching files from disk is forced off, because in hosted mode "the local disk" is the server's, not the caller's.
Without an allowlist the server refuses private addresses (localhost, RFC 1918 ranges,
169.254.*, *.internal, *.local) so a public deployment cannot be used to probe the network
it runs in. MAIL_ALLOWED_HOSTS=imap.example.com,smtp.example.com narrows it to named hosts.
docker build -t mail-mcp .
docker run -p 8080:8080 -e MAIL_ALLOWED_HOSTS=imap.example.com,smtp.example.com mail-mcpWhat hosting costs you. The mailbox password passes through the host on every request. The server keeps nothing — no accounts, no database, nothing written to disk, one throwaway server instance per request — but a mailbox password is not a scoped token, and no amount of "we store nothing" changes that. Run it yourself, or run it locally over stdio, whenever that matters.
Connection reuse
Logging in to IMAP costs a TLS handshake and a round trip, and providers rate-limit repeated logins hard. Authenticated connections are therefore pooled per mailbox and kept warm for five idle minutes, shared across requests in hosted mode. Work on one connection is serialised, because a single IMAP connection has one selected folder at a time.
Deploying
deploy.sh does the whole cycle on the server — pull, build, swap the container, verify, purge
the CDN cache:
./deploy.sh # the usual deploy
./deploy.sh --page-only # only replace landing.html in the running container, no rebuild
./deploy.sh --no-pull # deploy the working tree as it is
./deploy.sh --logs # follow the container log afterwardsCopy deploy.env.example to deploy.env on the server and set the port, container name,
PUBLIC_URL and, if the site sits behind Cloudflare, a zone id and an API token with the Cache
Purge permission. deploy.env is git-ignored, so server-specific values stay there.
The previous image is tagged :previous before every build, and a failed health check restores
it automatically and exits non-zero, so a broken build never stays deployed.
Landing page assets
assets/ holds everything the page references: favicon.svg (the source of every raster icon),
favicon.ico, the touch and PWA icons, site.webmanifest, and og-image.png — the 1200×630
preview, rendered from assets/og-card.html.
The PNG and ICO files are committed, so a normal build needs nothing extra. Regenerate them only
after editing favicon.svg or og-card.html:
npm run assets # headless Chrome does the rasterising; set CHROME=… if it is not foundDevelopment
npm run build # compile
npm run dev # tsc --watch
npm run typecheck # types only
npm run start # stdio mode
npm run start:http # hosted mode on PORT (default 8080)Layout:
src/
index.ts entry point, picks stdio or HTTP
server.ts builds a configured MCP server with every tool registered
http.ts hosted mode: landing page, stateless /mcp, per-request credentials
config.ts configuration from environment or headers
providers.ts host presets for the common mail services
mail-client.ts IMAP connection pool, folder resolution, bodies, attachments, SMTP
mime.ts charsets, HTML to text, addresses, quoting, subjects
dates.ts date arguments: ISO, `7d`, `yesterday`
tools/
helpers.ts shared argument schemas, result formatting, the read-only guard
core.ts mail_whoami
folders.ts folder tree and management
messages.ts listing, search, reading, threads, raw source
attachments.ts attachment listing and download
compose.ts send, reply, forward, drafts
actions.ts flags, moving, copying, deletingTo add a tool, call defineTool in the appropriate module: error handling and the read-only
guard are wired in automatically.
Troubleshooting
Symptom | Cause |
| Nearly always the account password where an app-specific one is needed, or IMAP not enabled in the provider's web interface. The message names your provider's requirement |
| Submission is port 587 with STARTTLS or 465 with TLS; port 25 is blocked by most networks |
| The account is not allowed to send as the configured From address |
Connect hangs, then times out | A TLS port configured as STARTTLS or the reverse. Set |
| The error lists the real folder names — providers localise them, and Gmail nests them under |
| UIDs belong to one folder. A message that was moved has a different UID there |
| For an internal server with its own CA, set |
| Working as intended: a guard rail stopped it |
Server will not start | Logs go to stderr with the |
A visual walkthrough with examples lives in landing.html at the repository root.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityDmaintenanceAn MCP server that enables AI models to read, search, and send emails via IMAP and SMTP protocols. It supports various providers like Gmail and Outlook, allowing for tasks such as retrieving unread messages, searching by sender, and managing mailbox folders.
- AlicenseAqualityDmaintenanceProvider-agnostic email MCP server that connects any IMAP mailbox to AI assistants, enabling email management through natural language.8AGPL 3.0
- Alicense-qualityBmaintenanceAn MCP server that receives emails on your domain and allows AI assistants to search, read, and manage them via natural language queries.1,200MIT
- Alicense-qualityDmaintenanceAn MCP server that gives AI assistants comprehensive access to Apple Mail accounts, enabling email discovery, reading, flag management, and server-side message retrieval.MIT
Related MCP Connectors
Shipmail MCP server for AI agent custom-domain email inboxes with REST API and webhooks.
Hosted email MCP for AI agents with inboxes, send/receive, memory, recovery, and credits.
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/amalychev/mail-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server