Email Worker Inbox
Receive inbound email with Email Workers, store messages in KV, and inspect them over HTTP - edge inbox pattern
Process inbound mail with the Cloudflare Email Workers email handler, parse MIME with postal-mime, store message summaries in Workers KV, and inspect them over HTTP.
Features
- Inbound
emailhandler with reject/store policy - Parses subject/body with
postal-mime GET /inboxandGET /inbox/:idfor inspection- Stores up to 50 recent messages with a 7-day KV TTL
- Local simulation via Wrangler’s
/cdn-cgi/handler/emailendpoint
API Reference
Email handler
Configured in the Cloudflare dashboard under Email Routing → route an address to this Worker.
The demo policy rejects:
- senders from
spam.exampleor@spam. - subjects containing
[spam]or starting withspam:
Rejected messages are still stored in KV with rejected: true so you can inspect them.
GET /inbox
Lists recent stored messages (newest first, max 50).
Example Request
curl "https://your-worker.workers.dev/inbox"Success Response
count number
Number of stored messages returned
messages array
Message summaries with id, from, to, subject, receivedAt, optional text / html, and rejection fields
{
"count": 1,
"messages": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"from": "sender@example.com",
"to": "inbox@example.com",
"subject": "Hello from Email Workers",
"receivedAt": "2026-07-23T12:00:00.000Z",
"text": "Hello from local email simulation.",
"messageId": "<test@example.com>",
"rejected": false
}
]
}GET /inbox/:id
Returns one stored message by id.
Example Request
curl "https://your-worker.workers.dev/inbox/550e8400-e29b-41d4-a716-446655440000"Success Response
Same shape as a single object in messages[] above.
Error Response
{
"error": "Message not found",
"code": "NOT_FOUND"
}Error Codes
404- Message id not found (NOT_FOUND)400- Missing message id (MISSING_ID)
Use Cases
- Build
support@/hello@edge inboxes - Prototype spam filters before forwarding
- Capture inbound mail for webhook-style automation
- Teach Email Workers + KV patterns end to end
Limitations
- Requires Email Routing enabled on a Cloudflare zone
- Stores truncated text/html previews (about 4KB each)
- Messages expire after 7 days (KV TTL)
- Does not forward or reply unless you extend the handler
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/email-worker-inbox.
import PostalMime from "postal-mime";import type { Env } from "../types/env";import type { InboxMessage } from "../types/inbox";import { createMessageId, storeInboxMessage } from "./inbox";import { shouldReject } from "./policy";/** * Process an inbound Email Worker message: parse, optionally reject, store in KV. */export async function handleInboundEmail( message: ForwardableEmailMessage, env: Env): Promise<void> { const parsed = await PostalMime.parse(message.raw); const subject = parsed.subject ?? message.headers.get("subject") ?? "(no subject)"; const rejectReason = shouldReject(message.from, subject); if (rejectReason) { message.setReject(rejectReason); } const stored: InboxMessage = { id: createMessageId(), from: message.from, to: message.to, subject, receivedAt: new Date().toISOString(), text: parsed.text?.slice(0, 4000), html: parsed.html?.slice(0, 4000), messageId: parsed.messageId, ...(rejectReason ? { rejected: true, rejectReason } : { rejected: false }), }; await storeInboxMessage(env.INBOX, stored);}Deployment
Create KV namespace
Create a KV namespace and set its id in wrangler.json for the INBOX binding.
Route email and test
In Email Routing, send an address to this Worker, then inspect with:
curl "https://your-worker.workers.dev/inbox"Local Development
cd apps/experiments/email-worker-inbox
npm install
npm run devSimulate an inbound email:
curl -X POST 'http://localhost:8787/cdn-cgi/handler/email?from=sender@example.com&to=inbox@example.com' \
--data-binary @- <<'EOF'
From: sender@example.com
To: inbox@example.com
Subject: Testing Email Workers
Message-ID: <test@example.com>
Content-Type: text/plain
Hello from local email simulation.
EOFThen inspect:
curl "http://localhost:8787/inbox"Local email simulation uses Wrangler’s /cdn-cgi/handler/email helper. Production delivery requires Email Routing configured on your zone.
Configuration
| Binding / dependency | Purpose |
|---|---|
INBOX (KV) | Stores message index + bodies |
postal-mime | Parses inbound MIME messages |
Cloudflare Features Used
- Workers - Edge compute runtime
- Email Workers - Inbound email handler
- Workers KV - Message storage and TTL