imap2mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
imap2mcp
A single-owner bridge that lets AI agents use your IMAP mailboxes through the Model Context Protocol (Streamable HTTP), with OAuth 2.1 authorization, encrypted mailbox credentials, and permissions you edit per client and per mailbox.
Status: Version 2 ("Reliable and observable"). v0 gave coarse mailbox-level grants; v1 added folder x operation rules with explicit deny and a Go sidecar with a header cache; v2 makes it something you can run unattended: every tool call is audited, failures are structured and diagnosable, provider outages and bad passwords are handled without retry storms, and a write whose outcome is unclear is verified against the server instead of being replayed. See docs/VERSION_PLAN.md for what each version promises, docs/PRD.md for the requirements, docs/DESIGN_V0.md, docs/DESIGN_V1.md and docs/DESIGN_V2.md for the binding design contracts, and docs/BENCHMARKS.md for measured numbers.
What it does
MCP over Streamable HTTP at
${BASE_URL}/mcp, stateless, bearer-token protected.OAuth 2.1 authorization server: authorization code with mandatory PKCE (S256), RFC 8414/9728 metadata, RFC 7591 dynamic client registration (or admin-created clients), RFC 8707 resource binding to
${BASE_URL}/mcp, refresh-token rotation. HTTP Basic auth and static API tokens are not accepted anywhere on/mcp.Folder x operation policy (v1). The owner edits, per OAuth client and mailbox, a list of rules
(folder, operation, allow|deny):Operation
Needs OAuth scope
Tools
search,read_headers,read_bodymail:readlist_folders,search_messages,read_messagedraftmail:draftcreate_draft(Drafts folder only)move,flagmail:organizemove_message(needsmoveon source and destination folder),set_flagsA folder selector is an exact IMAP path,
*(everything) orprefix/*(the prefix and its sub-folders); case-sensitive, nothing else is a wildcard. Any matching deny wins; otherwise any matching allow; otherwise deny. The token's scopes stay a ceiling. Rules are read on every call, so removing a rule or revoking a client applies to the next call (existing tokens included), and writes are re-checked right before they are sent. Search never touches, counts or reveals folders wheresearchis denied, and error messages do not reveal whether a denied folder exists. The v0 "presets" (read / draft / organize per mailbox) remain as shortcuts that expand to rules; upgrading from v0 migrates grants without widening anyone's access.Go sidecar for reads (v1). LIST/STATUS/FETCH/SEARCH run in
sidecar/(Go, go-imap v2), reached over a private Unix socket (DATA_DIR/sidecar.sock, mode 0600) with a per-process secret passed on the child's stdin. Node stays the policy authority and authorizes before and filters after every sidecar call. The sidecar caches UIDs, flags and envelopes in memory (never bodies), keyed by mailbox, folder, UIDVALIDITY and UID; UIDNEXT drives fetching new mail, and a periodic UID/flag reconciliation (SYNC_RECONCILE_SECS, default 30) catches expunges and flag changes made by other clients. Writes (APPEND, MOVE, STORE) stay in Node. If the sidecar is down, tools returnUPSTREAM_ERRORwhile Node restarts it; the cache is rebuilt from IMAP.Audit log (v2). Every tool attempt (allowed, denied, failed, unknown outcome) writes one row with client, mailbox, folder, UIDVALIDITY, UIDs, tool, outcome, error code and request id, never message content or credentials. Browse and export it (JSONL/CSV) under Audit in the admin UI or with
npm run audit:export; retention defaults to 90 days. By default it fails closed: if the audit row cannot be written, the tool does not run (AUDIT_FAIL_MODE=opento accept unaudited access).Structured errors and request ids (v2). Every error is
{code, message, requestId, retryable, operatorAction?}; the samerequestIdis in theX-Request-Idheader, the log and the audit row. Reads are retried at most twice inside a 30 s budget; writes are never replayed. After a lost connectioncreate_draft,move_messageandset_flagsare reconciled from server state or answeredUNKNOWN_OUTCOME. Seedocs/ERRORS.md.Authentication-failure latch (v2). When a mailbox's credentials are rejected the bridge stops trying (no lockout-causing retry loops) and tools answer
AUTH_FAILEDwith an operator action. Edit the password or press Retry in the admin UI to clear it; other mailboxes are unaffected.Health endpoints (v2). Unauthenticated
GET /healthz(liveness) andGET /readyz(database, key, sidecar, migrations), used by the DockerHEALTHCHECK; per-mailbox state is shown in the admin UI.Mailbox secrets encrypted at rest (AES-256-GCM, per-record IV, ciphertext bound to its table/row/column). The master key lives in a file outside the database. A missing or malformed key stops the server from starting; a wrong key makes every mailbox operation fail.
Safe IMAP behavior: TLS only with certificate validation, no plaintext fallback; reads use
BODY.PEEKso unread state is not changed; moves useUID MOVEorUID COPYplus flag andUID EXPUNGEof that UID only (never a plainEXPUNGE);\Deletedcannot be set through the tools.SSRF policy: a mailbox host must resolve to public addresses unless it is listed in
ALLOW_PRIVATE_HOSTS.
Related MCP server: mailpouch
What it does not do
No sending (no SMTP at all), no permanent deletion, no tamper-evident or off-host audit trail, no high availability, no multi-user tenancy (v3), no key rotation tooling yet. Not in v1 either: IMAP XOAUTH2 and CONDSTORE/QRESYNC (see docs/BACKLOG.md). Mail content is untrusted input: anything a client with read can read is exposed to that client and its model. See docs/THREAT_MODEL.md.
Quick start (Docker Compose)
git clone <this repo> && cd imap2mcp
# 1. Master key: outside the database, never committed, never in the image.
mkdir -p secrets data
openssl rand -hex 32 > secrets/imap2mcp_key
chmod 600 secrets/imap2mcp_key
chown 1000:1000 data # the container runs as uid 1000 ("node")
# 2. Required settings (no defaults for secrets).
export BASE_URL=https://mcp.example.com # public URL; the MCP resource is $BASE_URL/mcp
export SESSION_SECRET=$(openssl rand -hex 32)
# optional:
# export REGISTRATION_MODE=admin # default: dynamic
# export ALLOW_PRIVATE_HOSTS=mail.lan # comma list of hosts allowed to resolve to private IPs
docker compose up -d --build
# 3. First run: the server prints a one-time bootstrap token to its log.
docker compose logs imap-bridge | grep -A1 "bootstrap token"Then:
Open
${BASE_URL}/setup, paste the bootstrap token and choose the admin password (min. 12 characters). After this,/setupreturns 404 permanently. You can fix the token in advance withADMIN_BOOTSTRAP_TOKEN.Add a mailbox (host, TLS port, username, password), run Test connection, and pick the Drafts folder from the server's folder list.
Point your MCP client at
${BASE_URL}/mcp. It discovers OAuth, registers, and sends you to the consent screen, where you choose which mailbox access to allow. Afterwards refine the rules per folder and operation under Clients, revoke a client or its tokens, all with effect on the next call.
The Docker image builds the Go sidecar in a separate stage and includes it at sidecar/bin/sidecar.
Run it behind an HTTPS reverse proxy (the compose file binds 127.0.0.1:3000). With an https:// BASE_URL the session cookie is Secure and one proxy hop is trusted. See docs/OPERATIONS.md for backup, key handling and upgrades.
Without Docker
npm ci
npm run build:sidecar # needs Docker (golang:1.23-alpine) or a local Go toolchain; writes sidecar/bin/sidecar
npm run build
export BASE_URL=http://localhost:3000 SESSION_SECRET=$(openssl rand -hex 32) \
ENCRYPTION_KEY_FILE=$PWD/secrets/imap2mcp_key DATA_DIR=$PWD/data
npm startNode 22 or newer. ENCRYPTION_KEY (64 hex characters) is accepted as an alternative to ENCRYPTION_KEY_FILE; the file is preferred because environment variables leak into process listings and crash dumps.
Configuration
Variable | Required | Meaning |
| yes for production | Public URL. MCP resource/audience is |
| yes | 32-byte master key (hex or base64 in the file; 64 hex characters in the variable). No default. |
| yes | At least 32 characters. No default. The |
| no |
|
| no | Audit retention, default 90; 0 keeps forever. |
| no | Directory of |
| no | Default 3000. |
| no |
|
| no | Comma list of mailbox host names that may resolve to private/loopback addresses. Matched by exact host name. |
| no | Fixed one-time bootstrap token instead of a random one. |
| no | CORS origin for the machine-facing endpoints. |
| no | Path of the sidecar binary. Default |
| no |
|
| no | Interval of the sidecar's UID/flag reconciliation. Default 30. |
| no | Extra CA bundle the sidecar trusts for IMAP TLS (self-hosted mail servers, tests). |
Tests
npm test # everything
npm run test:unit
npm run test:integration # spawns the real server against an in-process IMAP-over-TLS fixture
npm run test:v1 # only the v1 end-to-end suites (policy matrix, sidecar boundary, sync correctness)
npm run smoke # build the Docker image and run a deployment smoke test (`npm run smoke:reuse` reuses imap2mcp:smoke)
npm run bench # v1 performance gate: 10,000 messages, 20 ms RTT, sidecar in Docker --cpus=2 --memory=2gThe integration suite needs openssl (to create a self-signed certificate for the fixture, injected through NODE_EXTRA_CA_CERTS so certificate validation stays on). If it is missing, those tests are skipped and the skip is printed; they are never reported as passing. The v1-* suites additionally need the built sidecar (npm run build:sidecar) and are skipped, with a printed reason, without it. Docker is needed only to build the sidecar without a local Go toolchain and for npm run bench. The fixture is a purpose-built fake (test/helpers/fakeImap.ts), not a production IMAP server: results show behavior against that fixture, not a provider compatibility matrix.
Documentation
docs/DESIGN_V0.md: binding v0 design contractdocs/DESIGN_V1.md: binding v1 design contract (policy rules, sidecar RPC, performance gate)docs/DESIGN_V2.md: binding v2 design contract (audit, failure handling, mutation safety, recovery)docs/INSTALL.md: installation walkthroughdocs/UPGRADING.md: upgrading between versions, pre-migration backupsdocs/TROUBLESHOOTING.md: symptoms, causes and fixesdocs/RECOVERY.md: restoring from backup, lost key, wrong key, corrupted databasedocs/ERRORS.md: error codes, retryability and what to dodocs/BENCHMARKS.md: v1 gate results with machine info; failed gates are reported as faileddocs/BACKLOG.md: deferred work (XOAUTH2, CONDSTORE/QRESYNC) and whydocs/THREAT_MODEL.md: what is protected, from whom, and what is notdocs/OPERATIONS.md: deployment, environment reference, health endpoints, keys, backup and restore, revocationdocs/CLIENTS.md: which clients are tested, registration modes, token lifetimesdocs/PRD.md,docs/VERSION_PLAN.md: requirements and release plan
Credits and license
MIT, see LICENSE. The v0 baseline was imported from mkrasselt1/imap-mcp-server (MIT); large parts have since been replaced (storage, authorization model, encryption, tools). Thanks to its author for the starting point.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Email infrastructure for AI agents — send, receive, search, and reply to email over MCP.
Programmable email inbox for AI agents — JMAP, PoW auth, stdio MCP server.
Private, EU-hosted email for AI agents over JMAP: read, search, reply, draft, organize, send.
Give AI agents their own email inboxes: list, read and send mail via scoped, revocable OAuth grants.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvider-agnostic email MCP server that connects any IMAP mailbox to AI assistants, enabling email management through natural language.813 PyPIAGPL 3.0
- AlicenseAqualityAmaintenanceAn MCP server that gives AI agents permission-gated, audit-logged access to private email providers (Proton Mail via Bridge and plain IMAP), running locally with OAuth-based authentication and human-controlled escalation for destructive operations.6660 npm17MIT
- AlicenseNot gradedqualityDmaintenanceA self-hosted, multi-mailbox MCP server that exposes IMAP/SMTP operations as tools for AI agents, enabling email management like listing folders, reading, searching, sending, and moving messages via natural language.MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI assistants to read, search, send, reply, forward, schedule, and organize email across multiple IMAP/SMTP accounts, including drafts, labels, bulk operations, real-time mailbox watching, verification-code capture, calendar extraction, and analytics. It runs locally over stdio or as a networked Streamable HTTP service with OAuth2 sign-in and provider auto-detection.27 npmISC