Blog

/

How Workers-native email routing actually processes your inbound mail

The phrase “email routing” hides more architecture than it reveals. This post opens the lid on the runtime that handles a single inbound message on Flowmails, from the moment SMTP lands at Cloudflare to the row in your D1.

The four pieces of the pipeline

An inbound message on Flowmails touches four Cloudflare primitives in order: Email Routing, a Worker, an R2 bucket, and a D1 database. Each one has a narrow job; the whole pipeline is short enough to read in a sitting.

  1. Email Routing accepts the SMTP connection for your zone and decides which Worker should receive the message.
  2. The Worker runs the routing logic: header parsing, address resolution, rule evaluation, attachment handling.
  3. R2 stores any attachments, keyed by message ID, with a short signed-URL expiry.
  4. D1 persists the message body, headers, routing decision, and any custom metadata your service attached.

What the Worker actually does

The Worker is the brain of the pipeline. When Email Routing delivers a message, the Worker receives an EmailEvent object with the raw RFC 822 payload and a reference to where attachments live in the Worker’s ephemeral store.

The Worker then runs three steps:

  1. Resolve the destination address against the routing rules stored in D1. Rules are domain-scoped; the Worker fetches the active rule set for the receiving domain in a single read.
  2. Move attachments from the ephemeral store into R2. The signed-URL lifetime defaults to seven days and is configurable per domain.
  3. Persist the message and the routing decision in D1 inside one transaction, then fire any webhook subscriptions that match the event type.

Why edge execution matters here

The Worker executes at the Cloudflare edge, in the region closest to where the message lands. For most inbound mail the total processing time is in the low tens of milliseconds, which is why webhook delivery feels synchronous even though the path is asynchronous.

It also means the pipeline is naturally multi-region without any configuration on your part. A customer in Tokyo and a customer in Frankfurt hit the same code path; the latency difference is geographic, not architectural.

What you can hook into

The pipeline exposes three integration points. Each one is optional and configured per domain.

Webhooks. Subscribed services receive a JSON payload on every inbound event, with the message ID, the routing decision, and a short-lived signed URL for the full message body. Webhook delivery has its own retry policy and a dead-letter log in D1.

Routing rules. Per-domain YAML-shaped rules that decide what happens to a message based on sender, subject, headers, or any custom tag your service has previously written. Rules are evaluated in the Worker, so the cost of a complex rule set is bounded by the time it takes to read it.

The REST API. Everything the Worker can do, your service can do too. List messages, search by header, send a new message, rotate API keys. The API is bearer-token authenticated and rate-limited per key.

What’s next on the runtime

The Workers AI hook is the next piece of the runtime. When the AI draft-and-reply feature ships in Q3 2026, it runs as a Worker step between routing-rule evaluation and D1 persistence, with the prompt templates and message context both read from your D1.

For a worked example of a service talking to this pipeline, see the REST API and webhooks post. For a higher-level view, the sending side walks the outbound path.

See the runtime in your own Cloudflare account.

Start free