Skip to content

Email Routing (incoming)

Cloudflare Email Routing accepts mail for your domain at Cloudflare's MX servers and forwards it according to rules you configure. Lumen uses the "Send to a Worker" action: every routed message is invoked as the Worker's email() handler.

Worker handler

worker/index.ts exports an email() handler that delegates to worker/email.ts. The handler:

  1. Looks up the to address in the addresses table.
  2. If no Lumen user owns the address, calls message.setReject(...) so the sending server gets an SMTP rejection.
  3. Otherwise parses the raw MIME with postal-mime, stores the metadata in D1, the raw .eml in R2 under raw/<userId>/<messageId>.eml, and each attachment under att/<userId>/<messageId>/<attachmentId>.
  4. Updates the contact list for the recipient with the sender.

Setting up routes

In the Cloudflare dashboard:

  1. EmailEmail Routing → enable for your domain. Cloudflare will add the MX and SPF records.
  2. RoutesCreate address. Pick Send to a Worker and select the lumen Worker.
  3. To accept any address, use Catch-all address with the same destination.

Catch-all

Lumen rejects unknown recipients by default. Enabling a catch-all route is fine — Lumen will still drop messages whose To: address is not registered to a user.

Adding addresses to a user

Each Lumen user lists their accepted addresses in Settings → Addresses. The first address added is automatically the primary. The primary address is the default sender when composing.

Verified destinations

Cloudflare Email Routing only delivers to verified destination addresses for non-Worker routes. Worker routes have no verification requirement, so any domain you control on Cloudflare can be used here.

Inbound size limit

Cloudflare currently caps inbound messages at ~25 MB. Lumen stores the exact raw bytes it receives, so make sure your D1 row size budget and R2 storage are sized appropriately.