an imap to mcp bridge with oauth support (on the agent side) and credential and permission management for imap-plain servers
A multi-agent, multi-user HTTP IMAP bridge that acts as a remote MCP server with built-in OAuth 2.1 authorization. Designed to let AI agents (like Claude.ai) securely access email on behalf of users, with granular per-agent permission control.
| Scope | Grants |
|---|---|
mail:folders | List mailbox folders |
mail:read | Read email messages |
mail:search | Search emails |
mail:modify | Move, flag, delete messages |
mail:send | Send emails via SMTP |
Important: The
-vvolume mount is required to persist your database (users, accounts, tokens) across container updates. Without it, all data is lost when the container is recreated.
docker run -d \
--name imap-bridge \
-p 3000:3000 \
-v imap-bridge-data:/app/data \
-e BASE_URL=https://your-domain.com \
-e ENCRYPTION_KEY=$(openssl rand -hex 32) \
-e SESSION_SECRET=$(openssl rand -hex 32) \
mkrasselt1/imap-mcp-serverTip: Save your
ENCRYPTION_KEY— if it changes, stored IMAP passwords become unrecoverable. Write it to an.envfile or use Docker secrets.
Or with Docker Compose:
git clone https://github.com/mkrasselt1/imap-mcp-server.git
cd imap-mcp-server
cp .env.example .env
# Edit .env with your values
docker compose up -d| Variable | Required | Description |
|---|---|---|
BASE_URL | Yes | Public URL of the server (e.g. https://mail.example.com). Must be HTTPS for Claude.ai. |
PORT | No | Listen port (default: 3000) |
ENCRYPTION_KEY | Yes | 64-char hex string for AES-256-GCM encryption. Generate with openssl rand -hex 32 |
SESSION_SECRET | Yes | Random string for session cookies. Generate with openssl rand -hex 32 |
Deploy behind a reverse proxy (nginx, Caddy, Traefik) with TLS. Claude.ai requires HTTPS.
https://your-domain.com/signup and create an accounthttps://your-domain.com/mcp/.well-known/oauth-authorization-serverClaude.ai IMAP Bridge User
│ │ │
│ GET /.well-known/oauth- │ │
│ authorization-server │ │
│───────────────────────────────────>│ │
│ { endpoints, scopes } │ │
│<───────────────────────────────────│ │
│ │ │
│ POST /oauth/register │ │
│ { redirect_uris } │ │
│───────────────────────────────────>│ │
│ { client_id } │ │
│<───────────────────────────────────│ │
│ │ │
│ Redirect to /oauth/authorize │ │
│ + PKCE code_challenge │ │
│───────────────────────────────────>│ Login form │
│ │──────────────────────────>│
│ │ Username + password │
│ │<──────────────────────────│
│ │ Consent screen │
│ │ (select account + perms) │
│ │──────────────────────────>│
│ │ Approve │
│ │<──────────────────────────│
│ Callback with auth code │ │
│<───────────────────────────────────│ │
│ │ │
│ POST /oauth/token │ │
│ + code_verifier (PKCE) │ │
│───────────────────────────────────>│ │
│ { access_token, refresh_token } │ │
│<───────────────────────────────────│ │
│ │ │
│ POST /mcp (tool calls) │ │
│ Authorization: Bearer <token> │ │
│───────────────────────────────────>│ IMAP │
│ { tool results } │ │
│<───────────────────────────────────│ │| Tool | Scope Required | Description |
|---|---|---|
list_folders | mail:folders | List all mailbox folders |
list_messages | mail:read | List messages with pagination. Supports includeBody to fetch message content inline. |
read_message | mail:read | Read full message by UID. Supports uids array to batch-read up to 10 messages in one call. |
search_messages | mail:search | Search by sender, date, subject, body. Supports includeBody to fetch message content inline. |
move_message | mail:modify | Move message between folders |
flag_message | mail:modify | Set read/unread, star, delete flags |
send_mail | mail:send | Send email via SMTP |
npm install
npm run dev # starts with tsx watchnpm run build # compile TypeScript
npm start # run compiled outputENCRYPTION_KEY safe; losing it means stored IMAP passwords become unrecoverableMIT
mkrasselt1/imap-mcp-server
April 11, 2026
April 13, 2026
TypeScript