# Mail Mcp

> Secure IMAP/SMTP/EWS/Graph API MCP server in Rust — Microsoft 365, Hotmail, Gmail, Zoho, OAuth2, multi-account

- **Type:** MCP server
- **Install:** `agentstack add mcp-tecnologicachile-mail-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [tecnologicachile](https://agentstack.voostack.com/s/tecnologicachile)
- **Installs:** 0
- **Category:** [Communication](https://agentstack.voostack.com/c/communication)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [tecnologicachile](https://github.com/tecnologicachile)
- **Source:** https://github.com/tecnologicachile/mail-mcp

## Install

```sh
agentstack add mcp-tecnologicachile-mail-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

mail-mcp
  
    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.4.8

- **`SAVE_SENT` is now per-account with a provider-aware default.**
  Previously, saving a copy of outgoing mail to the Sent folder via IMAP
  APPEND was controlled by a single global flag, `MAIL_SMTP_SAVE_SENT`. The
  problem: providers that **already save** sent mail server-side (Gmail,
  Zoho) ended up with **two identical copies** in Sent, while a generic SMTP
  server or Office 365 (which do **not** auto-save on SMTP submission) lost
  the copy entirely when the flag was `false`.
- **Provider-aware default** (when nothing is configured):
  - **Gmail** (`smtp.gmail.com`): saves server-side and deduplicates by
    Message-ID → the MCP does **not** append (`false`).
  - **Zoho** (`smtp.zoho.com`): saves server-side but does **not**
    deduplicate → the MCP does **not** append (`false`), avoiding the
    duplicate.
  - **Office 365 / generic SMTP**: do **not** auto-save on SMTP submission →
    the MCP **does** append (`true`), or the sent copy would be lost.
- **Per-account override**: `MAIL_SMTP__SAVE_SENT=true|false` takes
  priority over everything. The global `MAIL_SMTP_SAVE_SENT` still works as a
  coarse override (wins over the provider default, loses to the per-account
  override).
- Precedence: **per-account** → **global** → **provider-aware default**.

| Provider | Auto-saves server-side | MCP default |
|---|---|---|
| Gmail | Yes (with dedupe) | `false` |
| Zoho | Yes (no dedupe) | `false` |
| Office 365 (SMTP) | No | `true` |
| Generic SMTP / relays | No | `true` |

## What's New in v0.4.7

- **Critical fix — `graph_send_message` silently dropped attachments on
  threaded replies.** When called with `in_reply_to` + `attachments`, the
  `createReply → PATCH → send` flow included the attachments in the PATCH
  against `/me/messages/{id}`. Microsoft Graph treats `Message.attachments`
  as a navigation property and **silently discards the field** on PATCH
  (2xx response, no error), so the message went out as single-part
  `text/html` with no file. The MCP returned `status: ok` and the caller
  assumed success. Invisible data loss.
- **The fix:** in `send_via_reply()`, attachments are now uploaded one by one
  to `POST /me/messages/{draft_id}/attachments` between the PATCH and the
  send. Files ` markup into the
  recipient's inbox. v0.4.6 adds a real validator that **rejects** the tool
  call before any SMTP / Graph / EWS attempt if `body_text` or `body_html`
  contains tool-call wrapper syntax. The check is wired into all 5 send
  paths (`smtp_send_message`, `smtp_reply_message`, `smtp_forward_message`,
  `graph_send_message`, `ews_send_message`).
- The forbidden markers are case-insensitive and tightly scoped — only
  the pseudo-tags that have no legitimate use in human correspondence:
  ``, ``, ``, ``,
  ``, ``, ``,
  and ``. Generic technical content that happens
  to mention `` for an XML schema or `` in a code
  example still passes.
- **HARD RULE #1 wording updated** to announce the server-side rejection,
  so the LLM knows it's a hard contract — not a suggestion it can ignore.
- No breaking changes for clean callers: well-behaved messages send
  exactly as before.

## What's New in v0.4.5

- **`serverInfo` now reports `name="mail-mcp"` + the crate `version`** (the
  framework previously returned its own `rmcp 0.16.0`, which never changes
  between releases). Useful for verifying the active version with `/mcp`, and
  so any client-side cache keyed by (server, version) invalidates on each bump.
- **MCP instructions reorganized**: the 3 critical anti-concatenation rules
  (which in v0.4.3 and v0.4.4 sat at the end of the block and could be lost
  to truncation / diluted attention) now appear as **HARD RULE #1, #2, #3 at
  the TOP**, right after the title. Consolidated into 3 short paragraphs
  (previously 3 long sections, ~1500 characters combined).
- **No functional changes to the server.** Same SMTP/IMAP/EWS/Graph, same
  tool set, same behavior. Only the text exposed to the client changed.

### Important for these rules to take effect

Clients that resume a session with `claude --continue` (or `/resume`) do
**NOT** refresh the MCP `system_prompt` — they keep the one from that
session's first handshake. If your session predates v0.4.5, the rules won't
reach your context even if the on-disk binary is updated. To receive them,
start a NEW session in the project (not `--continue`).

## What's New in v0.4.4

- **Preview hygiene rule** in MCP `instructions`: when the LLM shows the
  user the email preview before sending, it should render ONE clean
  version of the body (markdown-style bullets, bold, links as text + URL)
  and state that the message will go multipart — but it must NOT dump
  the raw HTML source (``, ``, ``...) into the
  preview. Two reasons:
  1. The human reviewer wants to read the message, not audit markup —
     showing the HTML is noise.
  2. Exhibiting both the plain-text string AND the HTML string side by
     side in the preview is exactly the context that has historically
     led LLMs to concatenate them in the eventual tool call (the bug
     v0.4.3 documented). Hiding the HTML source from the preview
     removes the temptation.

  Complements the **PREVIEW DOES NOT EQUAL TOOL CALL** rule introduced
  in v0.4.3.

## What's New in v0.4.3

- **Server-side guidance against malformed tool calls.** The MCP
  `instructions` block now explicitly tells the calling LLM that
  `body_text` and `body_html` are TWO SEPARATE JSON fields and must
  NEVER be concatenated. Previous wording ("send BOTH body_text AND
  body_html") was ambiguous and some LLMs interpreted it as "concatenate
  both with `...` pseudo-tags inside a single
  `body_text` string". When that happens, the recipient sees garbled
  duplicated content, AND any later Claude session that opens the saved
  copy via this MCP gets a Usage Policy block (the leaked
  `...` looks like a prompt-injection attempt to safety
  filters). The new instruction shows a CORRECT vs WRONG example and
  bans pseudo-tags / tool-call wrapper syntax inside email fields.

## What's New in v0.4.2

- **Release pipeline fixed**: the `publish-npm` job in the CI release
  workflow has been disabled. It was inherited from the upstream fork and
  tried to publish to `@bradsjm/mail-imap-mcp-rs`, a scope this org does
  not own — every release was 404-ing on that step. See "Releasing" below
  for the full explanation and how to re-enable npm publishing if needed.
- **Auto-trigger releases on tag push**: `.github/workflows/release.yml`
  now fires on `push: tags: ['v*']`, so tagging `vX.Y.Z` and pushing is
  all it takes to cut a release. `workflow_dispatch` is retained as a
  manual escape hatch.
- **Cleanup**: removed the dangling `init-npm-placeholder.yml` workflow
  (also referenced the fork's npm scope).
- **docs**: README gains a "Releasing" section documenting the new flow
  and the npm decision.

## What's New in v0.4.1

- **Fix**: `save_to_sent_folder` now archives the exact RFC822 bytes that were
  sent (via `lettre.formatted()`), instead of a hand-rolled text-only stub.
  The Sent-folder copy keeps the HTML body, the multipart/alternative
  structure, and the RFC 2047-encoded subject — no more `???` where accents
  used to be, and HTML is no longer silently dropped.
- **Improved**: localized Sent-folder detection — `Enviado[s]`, `Elementos
  enviados`, `Enviadas`, `Itens enviados`, `Envoyés`, `Éléments envoyés`,
  `Gesendet`, `Posta inviata`, `Verzonden`, `Wysłane`, plus nested variants.
  Previously only English names were recognized, so Zoho/localized IMAP
  accounts fell through to a non-existent `"Sent"` folder.
- **Improved**: `smtp_forward_message` accepts `body_html` (was hardcoded to
  plain-text only).
- **Improved**: EWS send gains `bcc`, `in_reply_to`, `references` (via
  ``), plus full recipient + subject-length
  validation — now at parity with the SMTP and Graph send paths.
- **Improved**: Graph API threading fallbacks now log. `WARN` when the
  message-lookup HTTP call fails (rate limit, 5xx, permissions) so operators
  see threading degraded due to a real error; `DEBUG` when the original
  message is legitimately not found.
- **Refactor**: EWS XML parsing migrated from substring matching to
  `quick-xml`. Fixes a latent namespace-collision bug (`` vs
  ``), correctly decodes XML entities and CDATA, and handles
  attribute values containing `=` (common in base64-like EWS item IDs).
- **Cleanup**: zero warnings on `cargo build --release`.
- **Tests**: 64 (up from 47).

## Why This Project

| | mail-mcp | Typical email MCP |
|---|:---:|:---:|
| IMAP read/write | 18 tools | 3-5 tools |
| SMTP send/reply/forward | Yes | No or broken |
| Microsoft Graph API | Yes | No |
| EWS (Exchange Web Services) | Yes | No |
| OAuth2 (XOAUTH2) | Native | No |
| Multi-account | Yes | Single account |
| Microsoft 365 + Hotmail | Both work | Usually neither |
| Language | Rust (fast, safe) | TypeScript/Python |
| Tests | 64 unit + integration | Mocks only |
| Warnings in release build | 0 | Varies |

## Feature Matrix

| Provider | IMAP | SMTP | Graph API | EWS | OAuth2 | Multi-account |
|----------|:----:|:----:|:---------:|:---:|:------:|:-------------:|
| Microsoft 365 (enterprise) | Yes | Admin-dependent | Yes | **Yes** | Yes | Yes |
| Hotmail / Outlook.com | Yes | Blocked by MS | Yes | **Yes** | Yes | Yes |
| Gmail | Yes | Yes | — | — | Yes | Yes |
| Zoho | Yes | Yes | — | — | — | Yes |
| Fastmail | Yes | Yes | — | — | — | Yes |
| Any IMAP/SMTP server | Yes | Yes | — | — | — | Yes |

> **EWS is the simplest way to add Microsoft accounts** — single OAuth2 token for both reading and sending. Works even on tenants that block Graph API and IMAP.

## Quickstart — Let Claude Code do it

Copy and paste this prompt into Claude Code and it will install, compile, and configure everything for you:

```
Install and configure the mail-mcp MCP server from https://github.com/tecnologicachile/mail-mcp

1. Clone the repo, build with cargo build --release
2. Add the MCP server to .claude.json with the binary path
3. For Microsoft accounts: use EWS (simplest) — run device code flow with
   client_id d3590ed6-52b3-4102-aeff-aad2292ab01c and scope
   https://outlook.office365.com/EWS.AccessAsUser.All offline_access
   Then configure MAIL_EWS__USER and MAIL_EWS__REFRESH_TOKEN
4. For Gmail: configure MAIL_IMAP + MAIL_SMTP with App Password from
   https://myaccount.google.com/apppasswords
5. For Zoho: configure MAIL_IMAP + MAIL_SMTP with standard password
6. Enable write/send: MAIL_IMAP_WRITE_ENABLED=true, MAIL_SMTP_WRITE_ENABLED=true

My email accounts to configure:
- 
```

Replace the last line with your email(s). Claude Code will guide you through each step including the OAuth2 device code flow for Microsoft accounts.

## Manual Setup (2 minutes)

```bash
git clone https://github.com/tecnologicachile/mail-mcp.git
cd mail-mcp
cargo build --release
```

Add to your MCP client config (Claude Code, Cursor, etc.):

```json
{
  "mcpServers": {
    "mail": {
      "command": "./target/release/mail-mcp",
      "env": {
        "MAIL_IMAP_DEFAULT_HOST": "imap.gmail.com",
        "MAIL_IMAP_DEFAULT_USER": "you@gmail.com",
        "MAIL_IMAP_DEFAULT_PASS": "your-app-password",
        "MAIL_SMTP_DEFAULT_HOST": "smtp.gmail.com",
        "MAIL_SMTP_DEFAULT_PORT": "587",
        "MAIL_SMTP_DEFAULT_USER": "you@gmail.com",
        "MAIL_SMTP_DEFAULT_PASS": "your-app-password",
        "MAIL_SMTP_DEFAULT_SECURE": "starttls",
        "MAIL_IMAP_WRITE_ENABLED": "true",
        "MAIL_SMTP_WRITE_ENABLED": "true"
      }
    }
  }
}
```

That's it. Your AI agent can now read, search, send, reply, and manage emails.

### Microsoft Account? Use Graph API

Microsoft blocks SMTP on personal accounts. Use Graph API instead:

```json
{
  "env": {
    "MAIL_IMAP_DEFAULT_HOST": "outlook.office365.com",
    "MAIL_IMAP_DEFAULT_USER": "you@hotmail.com",
    "MAIL_IMAP_DEFAULT_PASS": "your-app-password",
    "MAIL_OAUTH2_DEFAULT_PROVIDER": "microsoft",
    "MAIL_OAUTH2_DEFAULT_CLIENT_ID": "9e5f94bc-e8a4-4e73-b8be-63364c29d753",
    "MAIL_OAUTH2_DEFAULT_CLIENT_SECRET": "none",
    "MAIL_OAUTH2_DEFAULT_REFRESH_TOKEN": ""
  }
}
```

Get your token in 1 minute with device code flow. See [Account Setup Guide](docs/account-setup.md).

## 30 MCP Tools

### Read (8 tools)

| Tool | What it does |
|------|-------------|
| `list_all_accounts` | **List all accounts with capabilities** (IMAP, SMTP, Graph, EWS) |
| `imap_list_accounts` | List IMAP accounts |
| `imap_verify_account` | Test connectivity and auth |
| `imap_list_mailboxes` | List folders |
| `imap_mailbox_status` | Message counts |
| `imap_search_messages` | Search with cursor pagination |
| `imap_get_message` | Parsed message (text, HTML, attachments) |
| `imap_get_message_raw` | RFC822 source |

### Write (11 tools)

| Tool | What it does |
|------|-------------|
| `imap_update_message_flags` | Add/remove flags |
| `imap_copy_message` | Copy (cross-account supported) |
| `imap_move_message` | Move to folder |
| `imap_delete_message` | Delete with confirmation |
| `imap_create_mailbox` | Create folder |
| `imap_delete_mailbox` | Delete folder |
| `imap_rename_mailbox` | Rename folder |
| `imap_append_message` | Append raw message |
| `imap_bulk_move` | Move up to 500 at once |
| `imap_bulk_delete` | Delete up to 500 at once |
| `imap_bulk_update_flags` | Flag up to 500 at once |

### Send (5 tools)

| Tool | What it does |
|------|-------------|
| `smtp_send_message` | Send email (text/HTML, CC/BCC) |
| `smtp_reply_message` | Reply with threading headers |
| `smtp_forward_message` | Forward with original inline |
| `smtp_verify_account` | Test SMTP connectivity |
| `graph_send_message` | Send via Microsoft Graph API (with reply threading) |

### EWS — Exchange Web Services (3 tools)

| Tool | What it does |
|------|-------------|
| `ews_search_messages` | Search emails via EWS (inbox, sent, drafts, etc.) |
| `ews_get_message` | Get full email content via EWS |
| `ews_send_message` | Send email via EWS |

### Attachments

Send files with any send tool. Two modes:

```json
// Large files — MCP reads from disk (recommended)
"attachments": [{"file_path": "/path/to/report.pdf"}]

// Small files — inline base64
"attachments": [{"filename": "note.txt", "content_type": "text/plain", "content_base64": "SGVsbG8="}]
```

Filename and MIME type are auto-detected from the file path. Reply with `include_original_attachments: true` to forward original attachments.

### Bulk Operations (2 tools)

| Tool | What it does |
|------|-------------|
| `imap_search_and_move` | Search + move matches |
| `imap_search_and_delete` | Search + delete matches |

### Setup Helper (1 tool)

| Tool | What it does |
|------|-------------|
| `get_setup_guide` | Provider-specific setup instructions (Microsoft OAuth2, Gmail App Passwords, Zoho, etc.) |

## Multi-Account

Configure as many accounts as you need:

```bash
# Gmail
MAIL_IMAP_GMAIL_HOST=imap.gmail.com
MAIL_IMAP_GMAIL_USER=me@gmail.com
MAIL_IMAP_GMAIL_PASS=app-password

# Microsoft 365
MAIL_IMAP_WORK_HOST=outlook.office365.com
MAIL_IMAP_WORK_USER=me@company.com
MAIL_OAUTH2_WORK_PROVIDER=microsoft
MAIL_OAUTH2_WORK_CLIENT_ID=your-client-id
MAIL_OAUTH2_WORK_CLIENT_SECRET=none
MAIL_OAUTH2_WORK_REFRESH_TOKEN=your-token

# Zoho
MAIL_IMAP_DEFAULT_HOST=imap.zoho.com
MAIL_IMAP_DEFAULT_USER=info@mydomain.com
MAIL_IMAP_DEFAULT_PASS=password
MAIL_SMTP_DEFAULT_HOST=smtp.zoho.com
MAIL_SMTP_DEFAULT_USER=info@mydomain.com
MAIL_SMTP_DEFAULT_PASS=password
MAIL_SMTP_DEFAULT_SE

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [tecnologicachile](https://github.com/tecnologicachile)
- **Source:** [tecnologicachile/mail-mcp](https://github.com/tecnologicachile/mail-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-tecnologicachile-mail-mcp
- Seller: https://agentstack.voostack.com/s/tecnologicachile
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
