A remote MCP server that connects Claude to your email — IMAP/SMTP plus semantic search, all in your own Cloudflare account.
Epistole (ἐπιστολή) — Greek for "letter" or "epistle"
Part of the Phantazein toolkit
| 📦 Install | 🏗 Architecture | 🛠 Tools | 💬 Prompts | 📂 Resources | ⚙️ Manual deploy |
Unlike local email MCP servers, Epistole runs in the cloud: it syncs continuously (not just when your laptop is open), works from any device including mobile, and never stores email data on your machine. Your own Cloudflare account, your own Worker, your own data.
You need a Cloudflare account (free) and Node.js. Then:
curl -fsSL https://raw.githubusercontent.com/Phantazein-apps/epistole/master/install.sh | bashThe installer will:
- Check dependencies and log you into Cloudflare if needed
- Ask for your email provider (Migadu, Gmail, Fastmail, etc.), address, and password
- Validate your IMAP credentials before proceeding
- Create all Cloudflare resources (D1, R2, Vectorize)
- Set credentials as encrypted Worker secrets
- Optionally configure a custom domain (e.g.
mail.yourdomain.com) - Deploy the Worker
- Configure Claude Desktop automatically
- Show connection details for any other MCP client
After it finishes, restart Claude Desktop and ask Claude to show your emails.
Claude Desktop → mcp-remote → Cloudflare Worker (/mcp)
│
┌───────────────┼───────────────┐
│ │ │
Workers AI Vectorize D1
(embeddings) (vector search) (metadata)
│ │
R2 IMAP / SMTP
(attachments) (your email server)
All email data stays in your own Cloudflare account. No third-party services. $0/month on the free tier for personal use.
| Tool | Description |
|---|---|
read_inbox |
List recent messages from any folder |
search_messages |
Search by sender, recipient, subject, body, date |
get_message |
Full message content with text, HTML, attachments |
get_emails |
Batch-fetch up to 20 messages by UID in one IMAP session |
send_message |
Compose and send new emails |
reply_to_message |
Reply or reply-all with proper threading |
forward_message |
Forward an existing message inline with quoted original |
save_draft |
APPEND a draft to the IMAP Drafts folder |
send_draft |
Send a saved draft via SMTP, then remove it from Drafts |
list_folders |
List all mailbox folders |
mark_read / mark_unread |
Toggle read status |
move_message |
Move messages between folders |
bulk_action |
Apply mark_read / mark_unread / delete / move to up to 100 UIDs at once |
| Tool | Description |
|---|---|
semantic_search |
Find emails by meaning using vector search |
get_attachments |
Serve attachments from R2 (no IMAP call) |
sync_now |
Trigger an immediate sync cycle |
sync_status |
Check progress, per-folder stats, errors |
find_by_thread |
Find thread by Message-ID or subject |
Workflow templates exposed via MCP prompts/list. They prime Claude to drive the existing tools toward a specific outcome — no new server logic.
| Prompt | What it does |
|---|---|
triage_inbox |
Walk recent inbox, bucket into act-now / reply / archive / ignore |
summarize_thread |
Chronological summary + decisions + open questions for a thread |
compose_reply |
Draft a reply for review (does not send) |
draft_from_context |
Compose a new email from a goal + context |
extract_action_items |
Pull open action items addressed to you, grouped by urgency |
summarize_meetings |
Roll up meeting-related mail (invites, recaps, follow-ups) |
cleanup_inbox |
Identify low-value mail and propose a bulk_action plan |
Read-only views exposed via MCP resources/list and resources/read. The {account} template variable is a parity hook for multi-account servers (Tier 3 roadmap); today it must equal the configured EMAIL_ADDRESS.
| URI | What it returns |
|---|---|
email://accounts |
Configured accounts (single-account today) |
email://templates |
Reusable text templates (acknowledge, decline, follow-up, intro, out-of-office, thank-you) |
email://scheduled |
Scheduled-send queue (empty until Tier 3 lands) |
email://{account}/unread |
Unread INBOX messages, most recent 20 |
email://{account}/mailboxes |
All IMAP folders for the account |
email://{account}/stats |
Index totals, per-folder counts, top senders, last sync |
If you prefer not to use the one-liner, or it doesn't work on your platform:
git clone https://github.com/Phantazein-apps/epistole
cd epistole
npm install
./setup.sh # creates D1, R2, Vectorize
npx wrangler secret put IMAP_HOST # repeat for all 11 secrets
npx wrangler deployThen add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"email": {
"command": "npx",
"args": [
"mcp-remote",
"https://email-mcp.YOUR-SUBDOMAIN.workers.dev/mcp",
"--header",
"Authorization: Bearer YOUR_MCP_TOKEN"
]
}
}
}| Provider | IMAP Host | SMTP Host | Notes |
|---|---|---|---|
| Migadu | imap.migadu.com |
smtp.migadu.com |
Full email as username |
| Fastmail | imap.fastmail.com |
smtp.fastmail.com |
App password required |
| Gmail | imap.gmail.com |
smtp.gmail.com |
App password required |
| Outlook | outlook.office365.com |
smtp.office365.com |
Port 587 for SMTP |
| Yahoo | imap.mail.yahoo.com |
smtp.mail.yahoo.com |
App password required |
| iCloud | imap.mail.me.com |
smtp.mail.me.com |
App password required |
A cron trigger runs every 15 minutes:
- Connects to IMAP, checks each folder for new messages (by UID)
- Fetches new messages (headers + first 20KB of body), stores metadata in D1
- Generates embeddings via Workers AI (
bge-base-en-v1.5) - Upserts vectors into Vectorize for semantic search
- Handles UIDVALIDITY changes (server rebuild) by re-indexing
First sync after deployment: call sync_now to bootstrap. Subsequent syncs are automatic.
Each sync run processes up to 200 messages across all folders (configurable via MAX_MESSAGES_PER_INVOCATION in src/sync/incremental.ts). This cap exists because Cloudflare Workers have a 30-second CPU time limit on cron triggers. At 200 messages per run and a cron every 15 minutes, the system indexes up to ~19,200 messages/day — enough to keep up with any normal mailbox.
If you have a very large mailbox (50K+ messages), the first full index may take several hours to catch up. During this period, semantic search is automatically disabled — it returns an index_incomplete error and tells Claude to use search_messages (live IMAP search) instead. This prevents stale or misleading results. Once the index reaches 90% of the server-side message count, semantic search re-enables itself.
Folders are synced in priority order: INBOX first, then Sent, Archive, and the rest alphabetically. This ensures your most important mail is searchable first.
Visit https://<your-worker>/status (e.g. https://email-mcp.your-subdomain.workers.dev/status or https://mail.yourdomain.com/status) to check sync progress anytime. The page is protected by the same email verification flow — you'll need to enter a one-time code sent to your inbox. No login or password required.
The optional WhatsApp mirror has been deprecated and is no longer registered with the Worker. Source has been moved to deprecated/ with a revival guide. The semantic_search tool now searches email only.
- Credentials stored as Worker secrets (encrypted at rest, never in code or logs)
- MCP endpoint protected by bearer token authentication
- Single-tenant — each user deploys their own Worker, no shared infrastructure
- No local data — everything lives in your Cloudflare account
| Service | Free tier | Typical personal use |
|---|---|---|
| Workers | 100K req/day | ~2K req/day |
| D1 | 5GB, 5M reads/day | <1MB |
| Workers AI | 10K neurons/day | ~6K neurons/mo |
| Vectorize | 30M queried dims/mo | ~8M stored dims |
| R2 | 10GB, 1M ops/mo | depends on attachments |
Personal use: $0/month. Heavy use (50K+ messages, constant searching): ~$5–8/month (Workers Paid plan base).
Last updated: May 6, 2026
Compared to yunfeizhu/mcp-mail-server, ai-zerolab/mcp-email-server, codefuturist/email-mcp, Improvado, and Gmail/Outlook MCP:
- Persisted semantic search over the archive (Vectorize +
bge-base-en-v1.5). No open-source IMAP/SMTP MCP ships this; competitors do IMAPSEARCHplus AI-on-fetch. - Remote MCP, claude.ai web and mobile compatible via Streamable HTTP + bearer token. Local stdio competitors can't be used outside Claude Desktop.
- User-owned single-tenant deploy. Your Cloudflare account, your D1, your Vectorize. Improvado is hosted but multi-tenant SaaS holding your credentials; everyone else is local-only.
- Always-on background sync every 15 min via cron. Inbox stays searchable when your laptop is off.
- R2-cached attachments served without an IMAP round-trip.
- Provider-agnostic IMAP/SMTP (Gmail, Outlook, Migadu, Fastmail, self-hosted Dovecot, anything RFC 3501). Gmail/Outlook MCPs lock you to one OAuth provider.
- $0/month on Cloudflare free tier for personal use.
- Tool surface is narrower than
codefuturist/email-mcp(19 vs 47 tools): no multi-account, no scheduling, no calendar extraction, no IDLE-based real-time triage. - Setup is heavier than an npx one-liner: 6 commands + 11 secrets + a Cloudflare account.
- No Docker image, no
.mcpbbundle, no install wizard yet.
MIT