使用说明
Email MCP Server
An MCP (Model Context Protocol) server that exposes common email operations as tools for LLM clients like Claude. Supports multiple named email accounts (e.g., work + Gmail) from a single server instance.
For more information, see my blog.
Example prompts
"Find the tax emails from my tax lawyers for 2025, and check the content and attachments to fully understand what documentation I need to provide. Please provide an action plan to get that documentation."
"Please help triage the emails in my inboxes. As per usual, flag anything that is actionable. Don't hesitate to read emails that you are uncertain about. For anything actionable, provide an action plan. For anything non-actionable, file according to the folder layout."
WARNING: This server performs real operations on your mailbox, for example moving emails around. By default it will not allow deletions and directly sending emails (this can be changed in the MCP config). The author assumes no responsibility for any loss of data or unintended consequences resulting from the use of this MCP server. Use at your own risk.
NOTE: That said, the author has been using this daily for weeks without issues.
Features / Tools
| Tool | Description |
|---|---|
| Discovery | |
getVersion |
Returns the server version |
listAccounts |
List configured account names (call first to discover accounts) |
listFolders |
List all mail folders (INBOX, Sent, Drafts, etc.) |
listFolderTree |
Full folder hierarchy with message/unread counts |
createFolder |
Create a new mail folder |
| Reading | |
listEmails |
List emails in a folder with pagination. Sortable by date (default), size, or sender |
readEmail |
Read the full content of a specific email. HTML bodies are converted to markdown by default |
getAttachment |
Download an email attachment by name. Images are returned directly; PDFs are converted to extracted text; other types as base64 blobs |
selfTestPdf |
Diagnostic: verify PDF text extraction works in this environment |
searchEmails |
Search by subject, sender, or body |
getUnreadCount |
Count unread emails in a folder |
getNextUnreadEmail |
Get oldest unread email with all headers. HTML bodies are converted to markdown |
| Triage | |
triageCompact |
Compact triage — from, subject, spam score, flags (start here) |
triageEmails |
Full-header triage — use when compact is not enough |
| Organizing | |
moveEmail |
Move a single email between folders (with optional mark-read) |
moveEmails |
Batch move emails to one target folder |
batchMoveEmails |
Move emails to multiple target folders in one call |
moveToSpam |
Move emails to the cached spam folder |
setEmailFlags |
Set any combination of seen, answered, forwarded, and flagged/starred on one or more emails |
deleteEmail |
Delete an email: moved to the trash folder, or removed permanently if the account has none. Disabled by default — opt in via EMAIL_ALLOW_DELETION=true (see Enabling permanent deletion) |
getTrashFolder |
Resolve and cache the trash folder that deleteEmail moves messages to (see Special folders) |
setTrashFolder |
Override the trash folder for this session |
| Spam | |
getSpamFolder |
Resolve and cache the spam/junk folder (configured, special-use flag, or well-known name; see Special folders) |
setSpamFolder |
Override the spam folder for this session |
| Composing | |
getDraftsFolder |
Resolve and cache the Drafts folder that saveDraft writes to (see Special folders) |
setDraftsFolder |
Override the Drafts folder for this session |
saveDraft |
Save a draft email for user review with CC/BCC (always available; preferred over send) |
sendEmail |
Send an email via SMTP with CC/BCC. Disabled by default — opt in via EMAIL_ALLOW_SENDING=true (see Enabling outbound sending) |
replyEmail |
Reply with proper threading headers and optional CC/BCC. Disabled by default — opt in via EMAIL_ALLOW_SENDING=true |
forwardEmail |
Verbatim forward (body never enters LLM context). Disabled by default — opt in via EMAIL_ALLOW_SENDING=true |
forwardEmailWithComment |
Forward with a comment prepended. Disabled by default — opt in via EMAIL_ALLOW_SENDING=true |
All tools (except listAccounts) require an account parameter — the name of the account to operate on (e.g., work, gmail).
Quick Start
Plugin users: install Email MCP from the AI Plugins marketplace for Claude Code or Codex. See the plugin guide for installation and local credential setup.
The fastest way to get started is to download a pre-built release from the Releases page. Two options are available:
New builds use the email-mcp-server- filename prefix shown below. Older releases use mcp-email-server-;
use the filenames attached to the release you download. When upgrading a manually configured client,
update its executable or JAR path to the new filename.
Claude Desktop users: the simplest install is the MCP Bundle, email-mcp-server-<version>-macos-aarch64.mcpb
or email-mcp-server-<version>-windows-x86_64.mcpb, see Setting up with Claude Desktop.
Option A: Native Binary (recommended)
No Java installation required. Download the binary for your platform:
| Platform | File |
|---|---|
| Linux x86_64 | email-mcp-server-<version>-linux-x86_64 |
| Linux aarch64 | email-mcp-server-<version>-linux-aarch64 |
| macOS Apple Silicon | email-mcp-server-<version>-macos-aarch64 |
| Windows x86_64 | email-mcp-server-<version>-windows-x86_64.exe |
On Linux and macOS, make the binary executable: chmod +x email-mcp-server-*
The macOS binary is signed and notarized, so Gatekeeper accepts it as downloaded. The one exception is a first launch while offline, because Gatekeeper fetches the notarization ticket from Apple; if that happens, clear the quarantine flag once:
xattr -d com.apple.quarantine email-mcp-server-<version>-macos-aarch64
Option B: Uber-jar
Runs on any platform with Java 21+ installed. Download email-mcp-server-<version>-runner.jar.
Then configure your MCP client (see Claude Desktop or Claude Code below).
Configuration
All credentials are passed via environment variables — nothing sensitive goes in source control. The LLM never sees these variables — it only sees tool names/descriptions and the text your tools return.
Accounts are defined by convention: EMAIL_ACCOUNTS_<NAME>_IMAP_* and EMAIL_ACCOUNTS_<NAME>_SMTP_*, where <NAME> is the account name in uppercase.
Per-account variables
| Variable pattern | Required | Default | Example |
|---|---|---|---|
EMAIL_ACCOUNTS_<NAME>_IMAP_HOST |
yes | imap.gmail.com |
|
EMAIL_ACCOUNTS_<NAME>_IMAP_USERNAME |
yes | you@gmail.com |
|
EMAIL_ACCOUNTS_<NAME>_IMAP_PASSWORD |
yes | abcd efgh ijkl mnop |
|
EMAIL_ACCOUNTS_<NAME>_IMAP_PORT |
no | 993 |
143 |
EMAIL_ACCOUNTS_<NAME>_IMAP_SSL |
no | true, or false on port 143 |
|
EMAIL_ACCOUNTS_<NAME>_SMTP_HOST |
yes | smtp.gmail.com |
|
EMAIL_ACCOUNTS_<NAME>_SMTP_USERNAME |
yes | you@gmail.com |
|
EMAIL_ACCOUNTS_<NAME>_SMTP_PASSWORD |
yes | abcd efgh ijkl mnop |
|
EMAIL_ACCOUNTS_<NAME>_SMTP_PORT |
no | 587 |
465 |
EMAIL_ACCOUNTS_<NAME>_SMTP_STARTTLS |
no | true |
|
EMAIL_ACCOUNTS_<NAME>_SMTP_SSL |
no | false, or true on port 465 |
|
EMAIL_ACCOUNTS_<NAME>_FROM |
no | the SMTP username | Jane Doe <jane@example.com> |
EMAIL_ACCOUNTS_<NAME>_DRAFTS_FOLDER |
no | auto-detected | INBOX.INBOX.Drafts |
EMAIL_ACCOUNTS_<NAME>_SPAM_FOLDER |
no | auto-detected | INBOX.INBOX.Junk |
EMAIL_ACCOUNTS_<NAME>_TRASH_FOLDER |
no | auto-detected | INBOX.INBOX.Trash |
For Gmail, create an App Password.
FROM is the From address on everything the account sends or drafts, as a bare address or as
Display Name <address>. It defaults to the SMTP username, which is the address itself for most providers;
set it when the SMTP login is not an email address, to send from an alias, or to add a display name. Reply-all
leaves the account's own addresses (the From address and the usernames) out of the recipients.
You can define as many accounts as needed. For example, to add a work and gmail account, set environment
variables for both EMAIL_ACCOUNTS_WORK_* and EMAIL_ACCOUNTS_GMAIL_*.
Transport security
With the default ports, IMAP is TLS on 993 and SMTP is port 587 upgraded with STARTTLS; the STARTTLS upgrade is required, so a server that does not offer it is refused rather than sent the password in the clear. The two other common setups need only the port, since the TLS mode follows it:
- SMTP on port 465 (implicit TLS, "SMTPS"), which some providers offer instead of 587: set
EMAIL_ACCOUNTS_<NAME>_SMTP_PORT=465. The connection is then encrypted from the first byte and the STARTTLS setting is ignored. - Plain IMAP on port 143: set
EMAIL_ACCOUNTS_<NAME>_IMAP_PORT=143. The connection is upgraded with STARTTLS when the server offers it, and stays unencrypted otherwise (for a local or test server).
For a non-standard port, set IMAP_SSL or SMTP_SSL explicitly; an explicit value always wins over the
port rule. Set SMTP_STARTTLS=false only for a server that really has no TLS at all.
Special folders
saveDraft, moveToSpam and deleteEmail need to know the account's Drafts, spam and trash folders. Most
servers need no configuration; each folder is resolved on first use, in this order:
- A folder set for the current session with
setDraftsFolder/setSpamFolder/setTrashFolder. - The configured
EMAIL_ACCOUNTS_<NAME>_DRAFTS_FOLDER/_SPAM_FOLDER/_TRASH_FOLDER. A configured folder that does not exist on the server is reported as an error rather than silently falling back, so the LLM can point out the misconfiguration and work around it with theset*Foldertool for the session. - The folder the server flags as
\Drafts/\Junk/\Trash(RFC 6154 special-use, supported by Gmail, Dovecot, Exchange and most others). - Well-known names such as
Drafts,[Gmail]/Drafts,INBOX.Drafts,Spam,Junk,[Gmail]/Spam,Trash,[Gmail]/Trash,Deleted Items. - Any folder whose last path element is
Drafts,Draft,Spam,Junk,Junk E-mail,Bulk Mail,Junk Email,Trash,Deleted Items,Deleted Messagesor a few localized trash names, which covers providers that nest everything under a namespace prefix (e.g. OVH'sINBOX.INBOX.Drafts).
Set the variable explicitly if your provider uses a name none of the heuristics find, or if auto-detection
picks the wrong folder. deleteEmail removes the message permanently only when no trash folder is found.
Network timeout
One setting covers every connection of every account:
| Variable | Default | Effect |
|---|---|---|
EMAIL_NETWORK_TIMEOUT |
60 |
Seconds to wait when connecting to an IMAP or SMTP server, for the server to answer, and for a write to complete. |
Without it a server that stops answering would hang the tool call, and with it the conversation, for good.
The wait is per socket read, not per operation, so a large attachment over a slow link is fine as long as
data keeps arriving. Raise it if a slow server times out on big searches; 0 disables the timeouts.
Equivalent system property: -Demail.network-timeout=60.
Safety flags — opt-in for irreversible actions
Permanent and outbound operations are opt-in for safety. By default the destructive/outbound tools are disabled and return an explanatory error so the LLM can tell the user what's happening and fall back to a safer alternative (moveEmail to a Trash folder, or saveDraft for the user to send manually).
| Variable | Default | Effect |
|---|---|---|
EMAIL_ALLOW_DELETION |
false |
Set to true to allow deleteEmail to actually delete messages. |
EMAIL_ALLOW_SENDING |
false |
Set to true to allow sendEmail, replyEmail, forwardEmail, and forwardEmailWithComment to actually transmit messages over SMTP. |
Equivalent system properties: -Demail.allow-deletion=true and -Demail.allow-sending=true. Restart the server after changing them.
Enabling permanent deletion
When EMAIL_ALLOW_DELETION is unset (or false), deleteEmail is still listed (so the LLM can discover it and explain the limitation), but every invocation is rejected before any IMAP call is made. Use moveEmail to a Trash folder as the safe alternative.
Enabling outbound sending
When EMAIL_ALLOW_SENDING is unset (or false), the four outbound tools above all return an explanatory error and do nothing. saveDraft is unaffected — it only writes to the IMAP Drafts folder (see Special folders), so the LLM can still compose messages for the user to review and send manually from their mail client. This is the recommended default workflow even when sending is enabled.
Setting up with Claude Desktop
The easiest way is the MCP Bundle. There is no config file to edit:
-
Download the
.mcpbfile for your platform from the Releases page:email-mcp-server-<version>-macos-aarch64.mcpboremail-mcp-server-<version>-windows-x86_64.mcpb. -
Install it: double-click the file, or in Claude Desktop open Settings → Extensions → Advanced settings → Install Extension… and pick the file. Claude Desktop shows its standard unsigned-extension notice, because the bundle file itself carries no signature (the binary inside it is signed); confirm with Install.
-
Installing does not ask for the account details, so open the extension's settings: in Settings → Extensions, find Email MCP Server and click Configure. Fill in the IMAP and SMTP server, username and password (passwords go to the operating system keychain). For Gmail, use an App Password. The optional fields can usually stay empty: From only if the SMTP username is not your email address or you want a display name, and the Drafts, Spam and Trash folder fields only for providers where auto-detection picks the wrong folder (see Special folders). Leave the two switches, Allow sending and Allow permanent deletion, off unless you need them. Save.
-
Make sure the extension is enabled and start a new chat. The email tools appear in the tool list; the account is called
defaultin the tools.
The bundle contains the same native binary as the standalone download, signed and notarized on macOS and Authenticode-signed on Windows. It configures a single account with the default ports (993 with SSL for IMAP, 587 with STARTTLS for SMTP); for several accounts, or other ports and SSL settings, use the manual route below.
If you prefer the manual route:
-
Download a release (see Quick Start) or build from source.
-
Edit the Claude Desktop config file
claude_desktop_config.json. On Windows it is located atC:\Users\<UserName>\AppData\Roaming\Claude\claude_desktop_config.json. On macOS it is at~/Library/Application Support/Claude/claude_desktop_config.json. -
Add the
emailentry to themcpServerssection. Here is an example with two accounts (workandgmail):
Using the native binary (Windows):
{
"mcpServers": {
"email": {
"command": "C:\\Users\\YourName\\path\\to\\email-mcp-server-windows-x86_64.exe",
"args": [
"-Dquarkus.mcp.server.stdio.enabled=true",
"-Dquarkus.config.locations=.",
"-Duser.dir=C:\\Users\\YourName\\claude"
],
"env": {
"EMAIL_ACCOUNTS_WORK_IMAP_HOST": "imap.example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_WORK_SMTP_HOST": "smtp.example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_GMAIL_IMAP_HOST": "imap.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_PASSWORD": "your-gmail-app-password",
"EMAIL_ACCOUNTS_GMAIL_SMTP_HOST": "smtp.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_PASSWORD": "your-gmail-app-password"
}
}
}
}
Using the uber-jar:
{
"mcpServers": {
"email": {
"command": "java",
"args": [
"-Dquarkus.mcp.server.stdio.enabled=true",
"-Dquarkus.config.locations=.",
"-Duser.dir=C:\\Users\\YourName\\claude",
"-jar",
"C:\\Users\\YourName\\path\\to\\email-mcp-server-runner.jar"
],
"env": {
"EMAIL_ACCOUNTS_WORK_IMAP_HOST": "imap.example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_WORK_SMTP_HOST": "smtp.example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_GMAIL_IMAP_HOST": "imap.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_PASSWORD": "your-gmail-app-password",
"EMAIL_ACCOUNTS_GMAIL_SMTP_HOST": "smtp.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_PASSWORD": "your-gmail-app-password"
}
}
}
}
- Restart Claude Desktop. The email tools should appear in the tool list.
Setting up with Claude Code
-
Download a release (see Quick Start) or build from source.
-
Edit
~/.claude.jsonand add anmcpServerssection. Here is an example with two accounts (workandgmail):
Using the native binary (Linux):
{
"mcpServers": {
"email": {
"command": "/path/to/email-mcp-server-linux-x86_64",
"args": [
"-Dquarkus.mcp.server.stdio.enabled=true"
],
"env": {
"EMAIL_ACCOUNTS_WORK_IMAP_HOST": "imap.example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_WORK_SMTP_HOST": "smtp.example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_GMAIL_IMAP_HOST": "imap.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_PASSWORD": "your-gmail-app-password",
"EMAIL_ACCOUNTS_GMAIL_SMTP_HOST": "smtp.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_PASSWORD": "your-gmail-app-password"
}
}
}
}
Using the uber-jar:
{
"mcpServers": {
"email": {
"command": "java",
"args": [
"-Dquarkus.mcp.server.stdio.enabled=true",
"-jar",
"/path/to/email-mcp-server-runner.jar"
],
"env": {
"EMAIL_ACCOUNTS_WORK_IMAP_HOST": "imap.example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_IMAP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_WORK_SMTP_HOST": "smtp.example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_USERNAME": "user@example.com",
"EMAIL_ACCOUNTS_WORK_SMTP_PASSWORD": "your-app-password",
"EMAIL_ACCOUNTS_GMAIL_IMAP_HOST": "imap.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_IMAP_PASSWORD": "your-gmail-app-password",
"EMAIL_ACCOUNTS_GMAIL_SMTP_HOST": "smtp.gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_USERNAME": "you@gmail.com",
"EMAIL_ACCOUNTS_GMAIL_SMTP_PASSWORD": "your-gmail-app-password"
}
}
}
}
- Restart Claude Code (or run
/mcpto reconnect). The email tools should appear in the tool list.
Note: Unlike Claude Desktop, Claude Code does not typically need the -Duser.dir and -Dquarkus.config.locations workarounds since it launches the server from a normal working directory.
Building from Source
Only needed if you want to contribute or run a development build. Building the uber-jar and the native images, running the integration tests, packing the MCP Bundles and signing the binaries are described in docs/DEVELOPMENT.md.
Troubleshooting
AccessDeniedException: C:\WINDOWS\system32\config: on Windows, Claude Desktop may launch the server withC:\WINDOWS\system32as the working directory, causing Quarkus to fail when scanning for config files. The-Duser.dirargument in the example config overrides the working directory, and-Dquarkus.config.locations=.prevents Quarkus from scanning restricted system directories. Point-Duser.dirto any directory your user can write to.- Server disconnects immediately: make sure
-Dquarkus.mcp.server.stdio.enabled=trueis in theargsbefore-jar. - No log output visible: Quarkus logs go to
email-mcp-server.log(in the working directory), not to stdout/stderr, to avoid interfering with the STDIO transport. Check that file for errors. With the MCP Bundle the working directory is your home directory, so the log is~/email-mcp-server.log. - Authentication errors: for Gmail, you need an App Password, not your regular password. Make sure 2-Step Verification is enabled on your Google account first.
- "Unknown account" errors: call
listAccountsfirst to see which accounts are configured. Account names are lowercase as defined in the environment variables (e.g.,work,gmail).
License
The server is released under the BSD 3-Clause License, see LICENSE. The release artifacts bundle third-party libraries under their own licenses; they are listed, with their licenses, in docs/THIRD-PARTY.md. Note in particular that PDF text extraction uses iText 7, which is licensed under the GNU Affero General Public License v3.0; see the note in that file.