How to Self-Host a Temporary Email Server (Without the Bloat)
Self-hosting temporary email usually starts the same way: someone installs a full mail stack, spends a weekend on Dovecot and SSL certificates, and ends up with a mail server that can do everything except what they actually wanted — a disposable inbox for signups. Here is the minimal architecture that works, and the parts you can safely skip.
The two-reason test
People self-host disposable email for exactly two reasons: privacy (you stop handing signups to a third-party inbox) and domain control (you can hand out addresses on your own domain, which public providers cannot offer). If neither reason applies to you, a public service is fine. If either does, keep reading.
The architecture that actually works
A working temp-mail server needs three moving parts, not the five a mail-course would have you believe:
- A mail transfer agent (MTA) on port 25. Postfix is the boring, correct choice. Its only job is to accept mail for your domains and hand it off.
- An application server with an embedded SMTP listener. Instead of writing mail to per-user maildirs, the app listens on a second port (say 2527) and receives everything Postfix relays to it.
- A web UI backed by a small database. Addresses are generated on demand; messages are stored and expire on a sliding TTL.
The glue is two Postfix settings. relay_domains lists every domain you own, and transport routes each one to smtp:[127.0.0.1]:2527. Postfix accepts the mail, the app decides whether the address exists. No Dovecot, no maildirs, no per-user provisioning.
What to skip (and why)
- IMAP/POP3. Disposable inboxes are read over HTTP, not synced to a mail client. Skipping Dovecot removes most of the complexity.
- Spam filtering. A temp address exists to receive verification codes. There is nothing to filter — you are the spam target by design.
- Virus scanning. Same logic. Scan nothing, store the raw body.
- DKIM/SPF for outbound. If you only receive, you can skip outbound signing entirely. Add it later if you want replies.
Storage: SQLite is enough
A single-file SQLite database handles millions of rows of short-lived messages. The pattern: each session gets an address and an expiry timestamp; a periodic sweep deletes expired rows. A sliding TTL (extend on read) keeps active inboxes alive without a second table. Rendering HTML mail inside a sandboxed iframe keeps the preview safe without a full sanitizer.
The DNS part
One MX record per domain, pointing at your server. If the domain lives on Cloudflare, add the MX with DNS-only mode (the grey cloud) — MX records do not need proxying. A few minutes of propagation and mail starts arriving.
When a single binary wins
A full stack (Mailcow, Mailu, Mail-in-a-Box) makes sense when you want real mailboxes for real people. For disposable inboxes, a small app — even one written with nothing but Node.js built-ins (node:http, node:net, node:sqlite) — runs on a $5 VPS and does the job in about a thousand lines. Fewer moving parts means fewer things to patch, which is the entire point of self-hosting.
If you want to see the minimal version running, the live demo at mail.howtageek.com is exactly this architecture: Postfix on port 25 relaying to an embedded SMTP server, SQLite storage, and a web UI you can use in ten seconds.