Content
# Email MCP Server
MCP server wrapping IMAP/SMTP with persistent IDLE, DKIM/SPF validation, and policy enforcement.
## Build
```bash
cd workspace/email-mcp
go mod tidy
go build -o email-mcp .
```
## Config
Copy `config.json.example` to `config.json` and fill password:
```json
{
"host": "mail.example.net",
"port": 993,
"smtp_port": 465,
"username": "bob@example.com",
"password": "...",
"policy": {
"always_bcc": "owner@example.com",
"trusted_senders": ["owner@example.com"],
"trusted_authserv_ids": ["mail.example.com"],
"dkim_fail_allowlist": ["newsletters.example.com"],
"dkim_enforced_senders": ["owner@example.com"],
"allowed_from_addrs": ["example.com"]
}
}
```
- **Sender trust:** Only addresses in `policy.trusted_senders` are treated as actionable. Untrusted senders return content without `policy_action` hints.
- **Always BCC:** Every outbound send automatically BCCs `policy.always_bcc`.
- **Safe-delete:** `mail.expire`, `mail.move`, and `mail.trash` use UID EXPUNGE (RFC 4315) — only the target message is expunged, never other `\Deleted` messages in the folder.
- **Attachment sandbox:** `mail.send` attachment reads are restricted to `policy.attachment_allow_dirs` (default: `/tmp`). Symlinks escaping the allowlist are rejected.
- **Signature verification:** DKIM/SPF/DMARC with client-side DKIM fallback. When `trust_mta_auth: true`, trusts `Authentication-Results` headers from `trusted_authserv_ids` only. **DKIM is now only enforced for senders listed in `dkim_enforced_senders`** (e.g. `["owner@example.com"]`); for all other senders DKIM failures are tolerated, but **SPF is still validated** — an SPF `fail` still blocks delivery. Use full addresses or bare domains (subdomain match: `mail.example.com` matches `example.com`).
- **From address allowlist:** `allowed_from_addrs` restricts which domains / addresses `mail.send` can use in the `From` header.
- **Retention:** Expire after 48h (configurable per-folder). `mail.expire` MOVEs to Trash, never hard-deletes, logs every message.
- **Forwarded emails:** `mail.fetch_attachments` auto-extracts `.eml` attachments from forwarded emails.
- **Header security:** All outbound headers are RFC 2047-encoded. `From` display names are structured via `net/mail.Address` — prevents header-injection spoofing.
- **Idempotency:** Duplicate `mail.send` calls with identical recipients, subject, body, html, from_addr, and attachments are blocked within a 60s window.
## Integration
- **MCP events:** `mail.received`, `mail.error` — pushed over MCP socket / WebSocket / webhook
- **IMAP IDLE:** Persistent connection with automatic reconnect — replaces polling
- **REST API:** Authenticated HTTP API (`/api/v1/tools/call`) for remote access from Sanctum or other HTTP clients
- **Webhooks:** New-mail notifications POSTed to `api.webhook_url` with 5s timeout, never blocks IDLE
- **Email client:** CLI wrapper at `bob/email-mcp-client` — `email search`, `email read`, `email send`, `email mailboxes`, etc.
## Transport Modes
| Mode | Flag / Config | Description |
|------|---------------|-------------|
| stdio | (default) | MCP over stdin/stdout — for local MCP client launch |
| TCP | `-tcp :8080` | MCP JSON-RPC over raw TCP — multiple clients |
| Unix socket | `-unix /path/to/sock` | MCP JSON-RPC over Unix socket |
| WebSocket | `-ws :8081` | MCP JSON-RPC over WebSocket — browser / remote clients, bearer-token auth, 10s auth deadline |
| HTTP render | `-http 127.0.0.1:8025` | HTML email renderer + health check (localhost only) |
| REST API | `config.api.enabled` | Authenticated HTTP REST API for remote access |
The REST API and WebSocket run alongside any of the other modes. The HTTP render server, REST API, and WebSocket use separate ports.