Disposable email inboxes that run entirely on Cloudflare's edge β no servers, no maintenance, no fuss.
Create a temporary address, receive mail in real-time, and watch it auto-destruct when the clock runs out. Perfect for sign-up confirmations, testing, or anywhere you need a throwaway inbox.
Note
This project was vibe coded β spec, architecture, and implementation were all built with AI-assisted development.
- Instant temporary inboxes β one click, no sign-up required
- Real-time delivery β emails appear the moment they arrive via WebSocket
- Self-destructing β inboxes auto-expire after 24 / 48 / 72 hours
- Plus aliases β
name+tag@domain.comroutes to the base inbox; the original recipient is preserved per message - Multi-domain β serve as many domains as you like from one deployment
- Secure rendering β HTML emails displayed in a sandboxed iframe
- Human verification β Cloudflare Turnstile protects inbox creation and admin login
- Zero infrastructure β 100% Cloudflare edge: Workers, D1, R2, KV, Durable Objects
- Replica-aware reads β request-scoped D1 Sessions + bookmarks keep inbox reads sequentially consistent when read replication is enabled
- Admin panel β manage domains, inspect inboxes, and browse seeded permanent inboxes
- WAF-ready β ships with a Cloudflare WAF configuration guide for free-tier edge protection
Get a local dev environment running in under a minute:
npm install
cp .dev.vars.example .dev.vars
npm run db:local:init
npm run devThat's it β open the URL printed in your terminal and create your first inbox.
Local development uses the Cloudflare Turnstile test keys in .dev.vars.example, so inbox creation works out of the box after copying the file. To use the admin panel locally, replace the placeholder ADMIN_PASSWORD in .dev.vars with a strong value, for example via npm run admin:password. Replace the Turnstile keys with a real widget's keys before deploying a public instance.
| Command | What it does |
|---|---|
npm run dev |
Start the local dev server |
npm run admin:password |
Generate a strong local admin password |
npm run email:local |
Send a test email to the local worker |
npm run db:local:reset |
Wipe and re-migrate the local D1 database |
npm run check |
Type-check the entire project |
npm run build |
Build the app for production |
Inbound Email
β Cloudflare Email Routing (catch-all)
β Worker email() handler
β Parse with postal-mime & store
ββ D1: email metadata
ββ R2: raw .eml, parsed body, attachments
ββ Durable Object: push WebSocket notification
β HTTP API uses request-scoped D1 Sessions + `x-d1-bookmark`
β React SPA updates the inbox in real-time
| Layer | Technology |
|---|---|
| Runtime | Cloudflare Workers |
| Frontend | React + Tailwind CSS (Vite) |
| Real-time | Durable Objects β Hibernation WebSocket API |
| Database | D1 (SQLite) + Drizzle ORM + D1 Sessions |
| Object Storage | R2 β raw .eml, parsed bodies, attachments |
| Sessions | KV β access tokens with auto-expiring TTL |
| API Router | Hono |
| Email Parsing | postal-mime |
| Human Verification | Cloudflare Turnstile |
Click the Deploy to Cloudflare Workers button at the top, or deploy manually with the repository script:
npm run deployThis applies remote D1 migrations and then runs wrangler deploy.
-
A Cloudflare account with Workers, Durable Objects, D1, R2, and KV enabled.
-
Email Routing enabled for each domain, with a catch-all rule pointing to this worker.
-
An
ADMIN_PASSWORDsecret:wrangler secret put ADMIN_PASSWORD
Must be β₯ 16 characters with at least 3 of 4 character classes (lowercase, uppercase, digit, symbol). Admin APIs fail closed if this is missing or too weak.
-
A Cloudflare Turnstile widget for your deployed hostname, plus Worker environment values for:
TURNSTILE_SITE_KEYβ public site key returned by/api/configTURNSTILE_SECRET_KEYβ secret used by the Worker to verify challenge responses
If Turnstile is not configured, flamemail fails closed and blocks inbox creation plus admin login.
-
Optional but recommended: enable D1 read replication in the Cloudflare dashboard for lower global read latency. flamemail already propagates D1 bookmarks on HTTP requests, so read replication can be enabled without app code changes.
- Inbox access β each temporary inbox gets a unique token stored in KV; expires with the inbox
- Admin access β password-authenticated sessions with 1-hour TTL
- Human verification β
POST /api/inboxesandPOST /api/admin/loginrequire a valid Turnstile token before the Worker creates state or evaluates admin credentials - WebSocket upgrades β require origin validation + a one-time ticket consumed on connect
- Replica consistency β inbox/admin HTTP requests propagate D1 bookmarks so replica reads stay sequentially consistent across requests
- Email rendering β HTML is sanitized and served inside a sandboxed iframe with strict CSP
- Inbound guardrails β rejects messages > 10 MiB, > 10 attachments, or when an inbox already holds 100 emails
src/
βββ client/ # React SPA (Vite)
β βββ components/ # UI components
β βββ hooks/ # React hooks (WebSocket, inbox state)
β βββ lib/ # API client, HTML sanitization, helpers
β βββ App.tsx # Routes & layout
βββ worker/ # Cloudflare Worker
βββ api/ # Hono route handlers
βββ db/ # Drizzle schema, relations, DB factory
βββ durable-objects/ # InboxWebSocket Durable Object
βββ services/ # Business logic (inbox lifecycle, R2 storage)
βββ email-handler.ts # Inbound email processing
βββ index.ts # Worker entry β fetch, email, scheduled
See spec.md for the full architecture, API reference, data-flow diagrams, and design rationale.
Contributions are welcome! The codebase follows a clear client/worker split β check out AGENTS.md for detailed change guidelines, recommended workflows, and security considerations.
# Verify your changes compile cleanly
npm run checkMIT β use it however you like.