Over 333 billion emails were sent daily in 2022 according to Radicati Group, and disposable email addresses now handle millions of those messages for privacy-conscious users. Developers building temporary email services face a unique challenge: processing inbound SMTP traffic at scale while storing messages for mere minutes before automatic deletion. This guide walks through every architectural decision — from choosing an MTA to designing the ephemeral storage layer — so you can launch a production-ready backend without over-engineering.
Quick Answer: A temporary email backend requires an SMTP server (Postfix or Haraka) to receive mail, a wildcard DNS MX record routing all subdomains to that server, a message parser (MimeKit or mailparser) to extract content, Redis or SQLite for sub-minute TTL storage, and a REST API serving messages to the frontend — all wrapped in automated cleanup jobs that purge expired inboxes every 60 seconds.
Why Temporary Email Architecture Differs from Standard Mail Systems
Ephemeral Data Model Changes Everything
Traditional mail servers optimize for durability — messages persist for years. Temporary email inverts that priority: every inbox has a TTL of 10–60 minutes, and the entire dataset turns over hundreds of times per day. This means write-heavy workloads, aggressive compaction, and zero backup requirements. Disposable email addresses (DEAs) serve as unique aliases per sender, letting users identify which service leaked their address — a pattern documented in the Wikipedia entry on disposable email addresses where each DEA forwards to a real mailbox but can be cancelled instantly if compromised.
No Outbound Delivery Simplifies the MTA
Because the service only receives mail, you skip SPF/DKIM signing, queue management for retries, and reputation monitoring. The MTA becomes a pure inbound listener. Postfix in "local delivery only" mode or Haraka with its plugin architecture both reduce memory footprint to under 50 MB versus 200+ MB for a full-featured MTA.
Wildcard Domains Enable Infinite Addresses
A single MX record for *.tempmail.example.com routes user123@tempmail.example.com and abc@tempmail.example.com to the same backend. The application layer parses the local-part to identify the target inbox. This eliminates per-user DNS provisioning and lets you spin up millions of addresses instantly.
Core Infrastructure: SMTP Reception Layer
Choose Postfix for Battle-Tested Stability
- Install Postfix on Ubuntu 22.04:
apt install postfix postfix-pcre— select "Internet Site" during setup. - Configure
/etc/postfix/main.cffor local-only delivery: setmydestination = tempmail.example.com,local_transport = lmtp:unix:/var/run/lmtp.sock, and disablesmtpd_bannerbranding. - Create a PCRE map at
/etc/postfix/recipient_canonical_mapswith/^(.+)@.+$/ $1@internalto normalize all recipients to a single internal domain. - Pipe incoming mail to your parser via LMTP:
lmtp unix - - n - - lmtpinmaster.cfpointing to your application socket. - Restart Postfix and test with
swaks --to test@tempmail.example.com --server localhost:25.
Or Use Haraka for Node.js Native Integration
Haraka's plugin system lets you write the message handler in JavaScript, sharing code with your API layer. Install with npm install -g Haraka, run haraka -i /opt/haraka, then enable rcpt_to.in_host_list and queue/smtp_forward plugins. A custom plugin in plugins/tempmail.js receives the parsed MIME object and pushes it to Redis in under 5 ms per message.
DNS Setup: One Wildcard MX Record
At your DNS provider, create MX 10 tempmail.example.com pointing to your mail server hostname, plus an A record for that hostname. Add TXT "v=spf1 -all" to reject outbound spoofing. Propagation takes under 5 minutes on Cloudflare or Route 53.
Message Parsing and Storage Design
Parse MIME Once, Store Structured JSON
RFC 5322 defines the Internet Message Format with headers, multipart boundaries, and encoded-words. Use mailparser (Node) or MimeKit (.NET) — both handle quoted-printable, base64, and charset conversion automatically. Extract from, to, subject, text, html, attachments[], and headers into a flat JSON object. Discard the raw MIME after parsing to save 60–80% storage.
Redis with TTL for Sub-Second Access
- Key pattern:
inbox:{address}:{messageId}→ JSON string, EX 3600 (1 hour max). - Index key:
inbox:{address}:list→ Redis List of messageIds, LTRIM to 50 most recent. - Address metadata:
inbox:{address}:meta→ Hash withcreatedAt,expiresAt,messageCount. - Cleanup: Lua script running via
EVALSHAevery 60 seconds scansinbox:*:metaand deletes expired keys in batch.
SQLite Alternative for Zero-Dependency Deployments
For single-node deployments under 10K messages/day, SQLite with WAL mode handles 500 writes/sec. Schema: messages(id, inbox_address, from_addr, subject, text, html, received_at) with index on (inbox_address, received_at DESC). A cron job runs DELETE FROM messages WHERE received_at < datetime('now', '-1 hour') every minute. File size stays under 100 MB with automatic vacuum.
REST API and Frontend Integration
Three Endpoints Cover All Client Needs
GET /api/inbox/{address}— returns metadata + last 50 messages, 200 OK or 404 if expired.GET /api/inbox/{address}/{messageId}— single message with full headers and attachments as base64.POST /api/inbox— creates new random address (e.g.,k7x9m2@tempmail.example.com), returns address andexpiresAt.
Rate-limit to 30 req/min per IP using Redis token bucket. Add Cache-Control: public, max-age=5 on list endpoint for browser caching.
WebSocket for Real-Time Updates
Clients subscribe to ws://api.tempmail.example.com/inbox/{address}. On message arrival, the LMTP handler publishes to Redis channel inbox:{address}; a Node worker pushes to connected WebSocket clients. Latency from SMTP receipt to browser notification: under 200 ms on same-region deployment.
CORS and Security Headers
Set Access-Control-Allow-Origin: https://tempmail.example.com (not *), X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin. No authentication needed — the address itself is the capability token.
Comparison: Temporary Email Backend Options
Choosing the right stack depends on scale, team expertise, and operational constraints. The table below compares four production-tested approaches.
| Stack | Max Throughput | Operational Complexity |
|---|---|---|
| Postfix + Redis + Node API | 100K msgs/day | Medium (3 services) |
| Haraka (Node) + Redis | 50K msgs/day | Low (1 process) |
| Postfix + SQLite + Go API | 10K msgs/day | Very Low (single binary) |
| Cloudflare Email Workers + KV | Unlimited (edge) | Low (serverless) |
Postfix + Redis handles the highest volume with mature tooling. Haraka consolidates everything into Node.js for teams avoiding C/C++ ops. SQLite removes the Redis dependency for small deployments. Cloudflare Email Workers (launched 2021) run at the edge with zero infrastructure but require Workers KV for storage and cost $0.50/million messages after free tier.
Common Mistakes and Expert Fixes
Mistake: Storing Raw EML Files on Disk
Why It Hurts: Filesystem inodes exhaust at 1M+ files; cleanup requires expensive find -mmin +60 -delete scans that block I/O.
Fix: Parse to JSON immediately; store in Redis or SQLite. One inbox = one key or row.
Mistake: No Backpressure on Inbound SMTP
Why It Hurts: A spam burst (10K msgs/sec) OOM-kills the parser; legitimate mail bounces.
Fix: Postfix smtpd_client_connection_rate_limit = 50 and anvil_rate_time_unit = 60s; Haraka connection.threshold = 100. Queue excess in Postfix's active queue (default 20K messages) rather than crashing the app.
Mistake: Using Sequential IDs for Inbox Addresses
Why It Hurts: Enumeration attack lets scrapers harvest all active inboxes in minutes.
Fix: Generate 12-char base36 strings (crypto.randomBytes(9).toString('base64url')) — 62^12 combinations, unguessable.
Mistake: Ignoring Attachment Size Limits
Why It Hurts: A 50 MB attachment fills Redis memory; eviction purges other users' mail.
Fix: Postfix message_size_limit = 10485760 (10 MB); parser rejects >5 MB attachments with 552 error. Store large attachments in S3 with presigned URLs if needed.
Pro Tips
- Run the LMTP handler in a separate process from the API — crash isolation keeps mail flowing during deployments.
- Add
X-TempMail-Expiresheader to every stored message so clients know TTL without extra API calls. - Log only
from,to,message-id,size— never log subjects or bodies (privacy compliance). - Deploy two mail servers in different AZs with identical config; DNS round-robin gives instant failover.
- Monitor
postfix/smtpd[pid]: connect from unknown[IP]rate — sudden spikes indicate abuse campaigns.
FAQ
What is a temporary email service backend?
A temporary email backend receives inbound SMTP messages for dynamically generated addresses, stores them for a short TTL (typically 10–60 minutes), and exposes them via API. Unlike standard mail servers, it has no outbound delivery, no user accounts, and no long-term storage.
How does it differ from a disposable email alias service?
Disposable email aliases (like user+tag@gmail.com) forward to a permanent mailbox and persist indefinitely. Temporary email creates standalone inboxes that self-destruct — no forwarding, no primary address linkage, no recovery after expiry.
Can I build this without managing an SMTP server?
Yes. Cloudflare Email Workers, AWS SES with Lambda, or ForwardEmail.net's API handle SMTP reception serverlessly. You write only the storage and API layer. Trade-off: less control over rate-limiting and attachment handling.
Why are my test emails not appearing in the inbox?
Common causes: DNS MX not propagated (wait 5 min), Postfix rejecting unknown recipients (check local_recipient_maps), parser crashing silently (check LMTP socket logs), or Redis TTL set to 0. Test with swaks --to test@yourdomain --server yourmx --tls and trace each hop.
What happens to temporary email when IPv6 becomes dominant?
SMTP over IPv6 works identically — Postfix and Haraka listen on :::25 alongside 0.0.0.0:25. DNSBL reputation shifts to /64 prefixes; configure postscreen_dnsbl_sites with IPv6-capable lists like Spamhaus ZEN. No architectural changes needed.
Conclusion
Building a temporary email backend is fundamentally simpler than a full mail system — no outbound queues, no reputation management, no durable storage. The entire stack fits in three components: an inbound MTA (Postfix or Haraka), a TTL-based store (Redis or SQLite), and a stateless API. Start with Haraka + Redis on a single $5 VPS; scale to Postfix + clustered Redis when you hit 50K messages/day. The wildcard DNS pattern and ephemeral data model eliminate the operational burden that makes traditional email infrastructure notorious.
- Wildcard MX + single MTA = infinite addresses with zero provisioning
- Parse once to JSON, store with TTL, purge via Lua script = zero manual cleanup
- Address as capability token = no auth system needed
- Backpressure at SMTP layer = survival under spam floods
0 comments:
Post a Comment