n24q02m/better-email-mcp

n24q02m/better-email-mcp

📇 ☁️ 🍎 🪟 🐧 - IMAP/SMTP email MCP server with App Passwords (no OAuth2). Auto-discovers Gmail, Outlook, Yahoo, iCloud. 5 composite tools: search, read, send, reply, forward. Multi-account support.

CLAUDE.md

CLAUDE.md - better-email-mcp

MCP Server cho Email (IMAP/SMTP). TypeScript, Node.js >= 24, bun, ESM. 6 composite tools, 20 actions (messages, folders, attachments, send, setup, help). Multi-account, App Passwords, auto-discovery.

Commands

# Setup
bun install

# Lint & Type check
bun run check                    # biome check + tsc --noEmit
bun run type-check               # tsc --noEmit only

# Fix
bun run check:fix                # biome fix + type check

# Test
bun run test                     # vitest (--passWithNoTests)
bun run test:watch               # vitest watch
bun run test:coverage            # vitest --coverage
bun vitest run src/tools/helpers/errors.test.ts   # single file

# Build & Dev
bun run build                    # tsc --build tsconfig.build.json + esbuild CLI
bun run dev                      # tsx watch dev server

# Docker
bun run docker:build
bun run docker:run

# Mise shortcuts
mise run setup     # full dev setup
mise run lint      # bun run check
mise run test      # bun run test
mise run fix       # bun run check:fix

Cau truc thu muc

src/
  init-server.ts                 # Entry point, env validation
  relay-setup.ts                 # Zero-config relay: create session, poll for config
  relay-schema.ts                # Relay form schema (email credential fields)
  auth/                          # OAuth 2.1 + DCR, per-user credential store
    stateless-client-store.ts    # HMAC-based stateless DCR (shared with Notion MCP)
    email-auth-provider.ts       # OAuthServerProvider for multi-user HTTP mode
    per-user-credential-store.ts # AES-256-GCM encrypted per-user credential storage
  transports/
    http.ts                      # Multi-user HTTP transport with OAuth 2.1
    credential-store.ts          # Single-user encrypted credential store (stdio mode)
  docs/                          # Markdown docs phuc vu qua MCP resources
  tools/
    registry.ts                  # Tool registration + routing
    composite/                   # 1 file per domain: messages, folders, attachments, send, setup
    helpers/                     # errors, config, html-utils, imap-client, smtp-client

Env vars

  • stdio mode (default): EMAIL_CREDENTIALS (bat buoc). Format: user@gmail.com:app-password
    • Multi-account: user1@gmail.com:pass1,user2@outlook.com:pass2
    • Custom IMAP host: user@custom.com:password:imap.custom.com
  • http mode: TRANSPORT_MODE=http, PUBLIC_URL, DCR_SERVER_SECRET
  • PORT (default 8080)
  • OUTLOOK_CLIENT_ID -- tu chon, cho self-hosted OAuth2 client

Code conventions

  • Biome: 2 spaces, 120 line width, single quotes, semicolons as needed, trailing commas none
  • Import: import type rieng, .js extension bat buoc, node: prefix cho builtins
  • tsconfig: strict: true, target es2021, module es2022, moduleResolution Bundler
  • Error: EmailMCPError + withErrorHandling() HOF. enhanceError() + suggestFixes().
  • Error details duoc sanitize de tranh lo secrets/passwords.
  • Test files co-located: errors.test.ts canh errors.ts
  • noExplicitAny: off (email API responses dung any)

CD Pipeline

PSR v10 (workflow_dispatch) -> npm + Docker (amd64+arm64) + GHCR + MCP Registry.

Luu y

  • Outlook/Hotmail/Live dung OAuth2 tu dong (Device Code flow). Token luu tai ~/.better-email-mcp/tokens.json.
  • Gmail, Yahoo, iCloud: dung App Passwords, KHONG phai password thuong.
  • Account resolution: filter theo email, id, hoac partial match.
  • Composite tool signature: async function toolName(accounts: AccountConfig[], input: TypedInput): Promise<any>
  • 3-tier token optimization: Tier 1 (compact), Tier 2 (help tool), Tier 3 (MCP Resources).
  • Pre-commit: biome check --write, tsc --noEmit, bun run test.
  • Infisical project: 3f23a1cb-d966-448d-91a1-bd1566a2361c

Modes (Phase L2 restored 2026-04-18)

Selected via MCP_MODE env var:

  • remote-relay (default): HTTP + delegated device-code OAuth flow tới Microsoft (login.microsoftonline.com/common/oauth2/v2.0/devicecode). Bắt buộc env OUTLOOK_CLIENT_ID (Azure app client ID). Token lưu tại ~/.better-email-mcp/tokens.json. Deploy tại https://better-email-mcp.n24q02m.com.
  • local-relay: HTTP + runLocalServer với relaySchema — user paste email:app-password vào /authorize form. Outlook accounts bị reject với hướng dẫn chuyển MCP_MODE=remote-relay. Gmail/Yahoo/iCloud/custom IMAP vẫn work qua paste form này.
  • stdio proxy: --stdio hoặc MCP_TRANSPORT=stdio. Backward compat.

Chuyển giữa remote-relay ↔ local-relay qua MCP_MODE env var. Default = remote-relay nếu không set.

Known bugs (phat hien 2026-04-18 E2E)

  1. Outlook Device Code flow (local-relay mode cũ): mo 2 tab auth giong het nhau:

    • Chỉ affect path local-relay với Outlook đã deprecated. Remote-relay (default) dùng mcp-core delegated device_code — không duplicate.
    • Nếu tái hiện trong remote-relay, debug: check if tryOpenBrowser bị call 2 lần hoặc browser auto-open + explicit link conflict.
  2. Browser UI stuck "Waiting for server..." (local-relay mode only):

    • Chỉ affect MCP_MODE=local-relay (paste form flow)
    • Same upstream bug nhu better-notion-mcp: packages/core-ts/src/relay/client.ts:sendMessage('complete') khong reach browser
    • See C:\Users\n24q02m-wlap\projects\mcp-core\CLAUDE.md Known bugs #2
    • Remote-relay không ảnh hưởng.
  3. Config storage path: TS server dung $APPDATA\mcp\Config\config.enc (khac Python servers $LOCALAPPDATA\mcp\config.enc). Khi debug/test, clean ca 2 paths + ~/.better-email-mcp/tokens.json de reset state.

  4. Outlook token email key in remote-relay: saveOutlookTokens fallback to OUTLOOK_EMAIL env hoac 'outlook-device-code' khi Microsoft token response khong include email field (device code mặc định không trả email). Workaround: set OUTLOOK_EMAIL env var khi self-host. Long-term fix: request openid email profile scopes + decode id_token trong onTokenReceived.

README.md

Better Email MCP

mcp-name: io.github.n24q02m/better-email-mcp

IMAP/SMTP email server for AI agents -- 6 composite tools with multi-account and auto-discovery

CI codecov npm Docker License: MIT

TypeScript Node.js IMAP/SMTP semantic-release Renovate

Features

  • Multi-account support -- manage 6+ email accounts (Gmail, Outlook, Yahoo, iCloud, Zoho, ProtonMail, custom IMAP)
  • App Passwords -- no OAuth2 setup required for most providers; clone and run in 1 minute
  • 6 composite tools with 20 actions -- search, read, send, reply, forward, organize, credential setup in single calls
  • Auto-discovery -- provider settings detected from email address, custom IMAP host supported
  • Thread-aware -- reply/forward maintains In-Reply-To and References headers
  • Tiered token optimization -- compressed descriptions + on-demand help tool + MCP Resources

Setup

With AI Agent -- copy and send this to your AI agent:

Please set up @n24q02m/better-email-mcp for me. Follow this guide: https://raw.githubusercontent.com/n24q02m/better-email-mcp/main/docs/setup-with-agent.md

Manual Setup -- follow docs/setup-manual.md

Tools

Tool Actions Description
messages search, read, mark_read, mark_unread, flag, unflag, move, archive, trash Search, read, and organize emails
folders list List mailbox folders
attachments list, download List and download email attachments
send new, reply, forward Compose, reply, and forward emails
setup status, start, reset, complete Credential setup via browser relay, status check, reset, re-resolve
help - Get full documentation for any tool

MCP Resources

URI Description
email://docs/messages Message operations reference
email://docs/folders Folder operations reference
email://docs/attachments Attachment operations reference
email://docs/send Send/compose reference
email://docs/help Full documentation

Zero-Config Setup

No environment variables needed. On first start, the server opens a relay setup page:

  1. Start the server (via plugin, npx, or Docker)
  2. A setup URL appears -- open it in any browser (relay: https://better-email-mcp.n24q02m.com)
  3. Enter your credentials in email:app-password format (comma-separated for multi-account)
  4. Credentials are encrypted and stored locally

Your credentials never leave your machine. The relay server only sees encrypted data.

For CI/automation, you can still use environment variables (see below).

Remote (HTTP Mode)

Run as a multi-user HTTP server with OAuth 2.1 authentication:

{
  "mcpServers": {
    "better-email": {
      "type": "http",
      "url": "https://better-email-mcp.n24q02m.com/mcp"
    }
  }
}

Self-Hosting (HTTP Mode)

docker run -p 8080:8080 \
  -e TRANSPORT_MODE=http \
  -e PUBLIC_URL=https://your-domain.com \
  -e DCR_SERVER_SECRET=$(openssl rand -hex 32) \
  n24q02m/better-email-mcp:latest

Users provide their own email credentials through the OAuth flow. No server-side EMAIL_CREDENTIALS needed.

Outlook OAuth Device Code

Outlook, Hotmail, and Live accounts use OAuth2 automatically. On first use with an Outlook account:

  1. The server prints a device code and a Microsoft login URL
  2. Open the URL in a browser and enter the code
  3. Sign in and authorize the app
  4. Tokens are saved locally at ~/.better-email-mcp/tokens.json

No App Password is needed for Outlook accounts.

Configuration

Variable Required Default Description
EMAIL_CREDENTIALS Yes (stdio) - Email credentials (user@gmail.com:app-password, comma-separated for multi-account)
TRANSPORT_MODE No stdio Set to http for remote mode
PUBLIC_URL Yes (http) - Server's public URL for OAuth redirects
DCR_SERVER_SECRET Yes (http) - HMAC secret for stateless client registration
PORT No 8080 Server port
OUTLOOK_CLIENT_ID No - Custom Azure AD client ID for self-hosted Outlook OAuth2

Multiple Accounts

EMAIL_CREDENTIALS=user1@gmail.com:pass1,user2@outlook.com:pass2,user3@yahoo.com:pass3

Custom IMAP Host

EMAIL_CREDENTIALS=user@custom.com:password:imap.custom.com

Search Query Language

Query Description
UNREAD Unread emails
FLAGGED Starred emails
SINCE 2024-01-01 Emails after date
FROM boss@company.com Emails from sender
SUBJECT meeting Emails matching subject
UNREAD SINCE 2024-06-01 Compound filter

Supported Providers

Provider Auth Save-to-Sent
Gmail App Password Auto (skipped)
Yahoo App Password Auto (skipped)
iCloud/Me.com App-Specific Password Auto (skipped)
Outlook/Hotmail/Live OAuth2 (Device Code) IMAP APPEND
Zoho App Password IMAP APPEND
ProtonMail ProtonMail Bridge IMAP APPEND
Custom Via email:pass:imap.host IMAP APPEND

Security

  • Credential sanitization -- Passwords never leaked in error messages
  • App Passwords -- Uses app-specific passwords, not regular passwords
  • Token storage -- Outlook OAuth tokens saved with 600 permissions
  • IMAP validation -- Search queries validated before execution

Build from Source

git clone https://github.com/n24q02m/better-email-mcp.git
cd better-email-mcp
bun install
bun run dev

License

MIT -- See LICENSE.