cfmail
Enables sending email through Resend as the default backend, allowing the agent to send replies, notifications, and other outbound mail automatically.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cfmailcheck my inbox for any verification codes from the last 24 hours"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cfmail · Give your Agent a mailbox it can use on its own
English | 简体中文
What is this
The goal is simple: let an Agent receive and send email on its own, with no human forwarding, approving, or clicking "send" in the middle. It runs on Cloudflare and has no web UI — this isn't an inbox for you to browse; it's a mailbox for an AI/program to use as its own.
Mail sent to
anything@your-domainis caught and stored automatically. The Agent searches it, reads the full text, replies, and forwards attachments on its own — you don't have to forward mail to it, and it doesn't have to wait for you to click send.
Someone emails you ──▶ Cloudflare receives it ──▶ parsed automatically, stored in a database and object storage
│
Agent ──asks a question / sends mail──▶ cfmail CLI (or MCP directly) ──▶ this service's API ──┘Startup cost is close to zero — Cloudflare's and Resend's free tiers are enough, and neither requires a credit card:
Piece | Free tier |
Receiving mail (Cloudflare Email Routing) | Unlimited, free by design |
Running the service (Cloudflare Workers) | 100,000 requests/day |
Storing mail bodies/index (Cloudflare D1) | 5 GB, 5M reads/day |
Storing raw attachments (Cloudflare R2) | 10 GB/month |
Sending mail (Resend, default backend) | 3,000/month, 100/day |
For a small project used by one person or a handful of Agents, these limits are hard to hit; upgrade later if volume actually grows.
It fits these situations:
Give an Agent a mailbox that is genuinely its own, so it can independently complete the whole "receive → understand → reply/forward" loop with no manual step in between.
Receive verification codes, notifications, bills, invoices on your own domain and let AI find and organize them for you.
Sync mail — body and attachments — to local disk on a schedule, and get pushed a chat message with a clickable local file the moment new mail arrives.
Technical details (database schema, search design, component breakdown, the dual send-backend design) are in ARCHITECTURE.md.
This document has two parts: Setup — deploying the service to your own Cloudflare account; and Usage — once it's deployed, how to let an Agent use it to send and receive mail.
Related MCP server: gmail-mcp
Setup: deploy to Cloudflare (~10 minutes)
Everything happens in your own Cloudflare account — mail only ever lives under your account, no one else can reach it.
What you need
A Cloudflare account (the free plan is enough).
A domain already added to that account (used both to receive mail and to reach the service).
Node.js 18 or newer installed locally.
Step 0: get the code, log in, create your local config
git clone <this-repo> && cd cfmail
npm install
npx wrangler login # log into your Cloudflare account in the browser
cp wrangler.jsonc wrangler.local.jsonc # your private config, never pushed to the repoAnything tied to your account — your domain, database ID — goes in
wrangler.local.jsonc. It's gitignored already; every command below picks it up automatically.
Step 1: create the database (stores mail metadata and bodies)
npx wrangler d1 create email_dbThe command prints a database_id — copy it into wrangler.local.jsonc at d1_databases[0].database_id.
Step 2: create object storage (stores raw mail and attachments)
npx wrangler r2 bucket create email-storeStep 3: set your domain
Open wrangler.local.jsonc and change routes[0].pattern to whatever subdomain you want, e.g. mail.yourdomain.com (it must be a domain in your Cloudflare account). This address is what the Agent will connect to.
Step 4: create the tables, set an access password, deploy
npm run db:remote # create the tables
npx wrangler secret put MCP_TOKEN # set an access password (see below)
npm run deploy # deployAccess password: after running that command, paste in a sufficiently long random string as the password —
openssl rand -hex 32works. The Agent needs this password to connect; never leak it. To rotate it, just rerun the command — the old password stops working immediately.
Step 5: route incoming mail to this service
Send every email addressed to your domain into this service (a one-time setup):
# replace <ZONE_ID> with your domain's Zone ID, and <API_TOKEN> with a Cloudflare API token that has "Email Routing edit" permission
curl -X PUT "https://api.cloudflare.com/client/v4/zones/<ZONE_ID>/email/routing/rules/catch_all" \
-H "Authorization: Bearer <API_TOKEN>" -H "Content-Type: application/json" \
--data '{"enabled":true,"name":"catch-all to worker","matchers":[{"type":"all"}],"actions":[{"type":"worker","value":["cloudflare-email"]}]}'Prefer clicking through the dashboard instead: Cloudflare dashboard → your domain → Email Routing → Catch-all → action "Send to a Worker" → pick cloudflare-email.
If this domain has never had Email Routing turned on, enable it in the dashboard first (it adds the DNS records mail delivery needs automatically).
Done! Mail to anything@your-domain is now caught, and the service is live at https://your-subdomain. To check: send a test email to test@your-domain, then within a few seconds npx wrangler tail cloudflare-email should show it being processed; the Agent will be able to find it once you've set up "Usage" below.
Optional: enable sending
Skip this step and the service can only receive mail, not send it. Two backends are supported, and Resend is the default:
Option one, Resend (recommended):
Sign up at Resend and add your domain — use the root domain (
yourdomain.com) directly, no need for a subdomain.Add the three DNS records it gives you, in Cloudflare DNS:
Type
Name
Value
Proxy
MX
sendthe address Resend gives you, priority 10
—
TXT
sendv=spf1 include:amazonses.com ~all—
TXT
resend._domainkeythe DKIM public key Resend gives you
DNS only (grey-cloud it)
This MX record lives on
send.yourdomain.com, so it doesn't conflict with Email Routing on the root domain. The DKIM record must have the proxy turned off — leaving it proxied fails verification.Set the key as a secret:
npx wrangler secret put RESEND_API_KEY -c wrangler.local.jsonc
The free tier is 3,000 emails/month, 100/day — enough to get started; pay as you grow, or switch to the option below.
Option two, Cloudflare's built-in sending: confirm wrangler.local.jsonc has "send_email": [{ "name": "EMAIL" }] (already in the template), then do a one-time Email Sending onboarding for your domain under Cloudflare's Email dashboard. If you're only sending to addresses you've already verified under Email Routing → Destination addresses, you can skip onboarding entirely and send for free right away.
With neither configured, sending returns a "no send backend available" message that explains what to set up; receiving and querying are unaffected. For details on sending — attachment size limits, sender restrictions, how to debug a failure — see ARCHITECTURE.md and cli/README.md; when a send fails, the Agent reads the error code and tells you what went wrong, so you don't need to memorize these limits up front.
Ongoing maintenance after deploying
npx wrangler tail cloudflare-email # tail incoming mail and errors live
npx wrangler secret put MCP_TOKEN # rotate the access password
npx wrangler d1 execute email_db --remote --command "SELECT id,subject,from_addr,date FROM emails ORDER BY date DESC LIMIT 10"
wrangler.local.jsonconly exists on your machine — don't delete it by accident. If you do, redo "Step 0" and fill your database ID and domain back in.
Usage: let an Agent send and receive mail
Once deployed, there are three ways to wire it up to an Agent. Skills are the recommended path — it's the least fuss, and closest to the goal of "the Agent handles mail on its own."
Preferred: use the skills (recommended)
The skills/ directory has two skills that teach an Agent to work through the cfmail command-line tool:
skills/
email-inbox/ for a regular user: read and send mail with a bound Key
email-admin/ for an admin: open mailboxes, issue/revoke Keys, configure new-mail alertsThe two work together: the admin uses email-admin to issue a Key for a mailbox address, and the user puts that Key into email-inbox to send and receive mail.
Step 0, install cfmail (needs Node 20+):
npm install -g cfmailStep 1, copy the skills into the Agent's skills directory. For Claude Code, that's .claude/skills/:
cp -r skills/email-inbox your-project/.claude/skills/
cp -r skills/email-admin your-project/.claude/skills/You can also symlink the whole
skills/directory:ln -s /path/to/cfmail/skills your-project/.claude/skills.
Step 2 (admin), open a mailbox:
cfmail admin setup --base https://your-subdomain --key <admin-MCP_TOKEN> # one-time
cfmail admin create-key alice@your-domain # prints a plaintext Key, shown only onceOther admin commands: list-keys (see what's been issued), delete-key <address> (revoke), webhook --set whk_xxx (push new mail to chat, optional — see cli/README.md).
Step 3 (user), configure that Key:
cfmail setup --base https://your-subdomain --email alice@your-domain --key <the-key-from-step-2>Once it's configured, just talk to the Agent:
"Check if there's any new mail" / "Find that verification code email"
"Reply to that invoice email and confirm we got it"
"Forward that attachment to accounting"
It picks the right command on its own, reading full text, fetching attachments, and replying as needed. Mail is always sent from the address bound to the Key — that's enforced server-side and can't be changed.
If you also want mail synced to local disk, with a chat push carrying a clickable file link when new mail arrives — that's a separate, optional add-on outside the skills flow:
cfmail sync --dir ~/cfmail --notify whk_your-keyPut it on a schedule with launchd/cron. Directory layout, dedup rules, and how this differs from admin webhook are all in cli/README.md.
Security note:
email-adminholds the highest-privilege admin key — keep it on the admin's own machine only, never hand it to a regular user.
Alternative: use the cfmail command line directly
Without the skills, an Agent (or you) can just run commands:
cfmail unread # fetch the latest unread mail
cfmail search "invoice" # full-text search, Chinese included
cfmail read <email-id> # read the full text and attachment list
cfmail send --to a@x.com --subject "subject" --text "body" # send one
cfmail reply <email-id> --text "reply text" # reply within the original thread
cfmail config # see which mailbox this config points atManaging multiple mailboxes on one machine, running several Agents concurrently, the local archive layout, and every flag — the full reference is cli/README.md (every command also answers --help).
Alternative: skip the CLI, connect the service as MCP directly
If you'd rather not install the CLI, you can point an MCP-capable AI client straight at the service:
claude mcp add --transport http email https://your-subdomain/mcp \
--header "Authorization: Bearer your-password"Other MCP clients use a config file:
{
"mcpServers": {
"email": {
"url": "https://your-subdomain/mcp",
"headers": { "Authorization": "Bearer your-password" }
}
}
}Once connected, just ask in plain language: "search for mail containing 'invoice'", "open the first one and download the attachment" — under the hood this uses tools like search_emails / list_emails / get_email / get_attachment / send_email, chosen automatically by the AI; you don't need to remember their names. This path doesn't get you local archiving or multi-mailbox management — those are cfmail-only.
FAQ
The service URL won't load / connection reset: don't use the default
*.workers.dev(blocked in some regions) — use your own domain (which is what this project does by default).A test email you sent bounced (550 SPF): that's a sender-side validation issue; sending from a normal mailbox (Gmail, QQ, Outlook, etc.) isn't affected.
A mail you just sent doesn't show up yet: there's a few seconds of delay between receiving and indexing — wait and check again, or use
npx wrangler tail cloudflare-emailto see if it arrived.Getting a 401: check that
Authorization: Bearer your-passwordis set correctly.
For contributors: local development
cp .dev.vars.example .dev.vars # fill in a local access password
npm run db:local # create local database tables
npm run dev # start locally on :8787
MCP_TOKEN=your-local-password node scripts/mcp-smoke.mjs # smoke-test the local API
npm test # unit tests
npm run typecheck # type checkingSmoke-test against production: BASE="https://your-subdomain" TOKEN="your-password" node scripts/remote-check.mjs
License
MIT — free to use, modify, and distribute.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to send emails via Cloudflare's Email Service. Provides both MCP server integration for AI tools and a REST API for traditional applications with support for HTML content, attachments, and secure authentication.2MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that connects Gmail to AI assistants, enabling search, read, send, reply-all, forward, attachment handling, and draft management across multiple Google accounts, deployable on your own Cloudflare Worker.231MIT
- AlicenseNot gradedqualityCmaintenanceConnects AI agents to self-hosted Stalwart mail servers via a Cloudflare Worker and JMAP, enabling mailbox search, reading, listing, and two-step draft-and-send email operations through MCP.MIT
- AlicenseNot gradedqualityCmaintenanceDeploys a self-hosted Cloudflare email service providing short-lived mailboxes with a JSON API and MCP endpoint for automated testing and AI agent signup, verification, and magic-link flows.9MIT
Related MCP Connectors
Hosted email MCP for AI agents with inboxes, send/receive, memory, recovery, and credits.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Authenticated email gateway for AI agents — per-agent inboxes, HITL approval, SPF/DKIM verified.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/askie/cfmail'
If you have feedback or need assistance with the MCP directory API, please join our Discord server