site.developers.cloudflare.com: what Email Workers can do, and where they stop

The Email Workers runtime API and the Email Sending binding as Cloudflare documents them, with the rules and limits that decide what you can build, and what MarkRelay builds on them.

Published by
MarkRelay Research
Updated
Sources
5 primary sources, linked below

Summary

An Email Worker is a Worker with an email() handler that Email Routing calls for each message routed to it. It sees the envelope sender and recipient, the headers and the raw MIME stream, and can reject the message with a permanent SMTP error, forward it to verified destination addresses, or reply once to the sender from the receiving domain if the incoming mail passed DMARC. Sending anything else, such as a notification, goes through the Email Sending send_email binding: from an onboarded domain, up to 50 recipients and 5 MiB per message. Storing mail, showing it to people and giving apps an API are left to you. MarkRelay is that layer: an Email Worker plus webmail and an HTTP API, deployed into your own Cloudflare account.

Key findings

  1. 1email(message, env, ctx) receives from, to, headers, raw, rawSize and canBeForwarded.
  2. 2setReject(reason) rejects with a permanent SMTP error; forward() delivers only to verified destination addresses and keeps only X- headers you add.
  3. 3reply() works once per message, only to the original sender, only from the receiving domain, only if the incoming mail has a valid DMARC result and at most 100 References entries.
  4. 4Sending with the send_email binding needs an onboarded, verified sender domain; up to 50 recipients and 5 MiB per message, 32 attachments; new accounts start with a conservative daily quota.
  5. 5Inbound mail is limited to 25 MiB; Email Workers count toward normal Workers CPU and memory limits, and binding sends show as "dropped" in the Email Routing summary even when delivered.

Questions this report answers

Asked by real people, quoted as they wrote them.

“Is it possible to use email workers for notifications?”

r/CloudFlare

Yes, through the Email Sending send_email binding rather than the email() handler: from an onboarded domain, to up to 50 recipients a message. Before the domain is onboarded you can send only to verified destination addresses.

“Am I thinking about Email Routing the right way?”

r/CloudFlare, 9 comments

Email Routing decides where each address goes: a verified address, a Worker, or drop. An Email Worker is where logic lives: reject, forward, reply, or store. Storage and an inbox are not part of either; MarkRelay adds them in the same account.

“Can Email Routing send emails?”

r/CloudFlare

An Email Worker can reply once to the sender of a message it received. Sending new mail needs Email Sending, on Workers Paid for recipients outside your verified addresses.

“email to webhook”

Google and Bing search suggestion

An Email Worker can read the raw message and fetch() any URL, so it can post mail to a webhook; you write the MIME parsing, retries and signing. MarkRelay does this out of the box with signed webhooks.

What an Email Worker can do with a message

from, to, headers, raw, rawSize

What it does
Envelope, headers, raw MIME stream, size
Rules
Read-only

setReject(reason)

What it does
Rejects with a permanent SMTP error
Rules
Not stated

forward(rcptTo, headers?)

What it does
Delivers to another address
Rules
Verified destinations only; only X- headers can be added

reply(message)

What it does
Threaded reply to the sender
Rules
Once per message; to the sender; from the receiving domain; valid DMARC; ≤100 References

send_email binding

What it does
Sends new mail
Rules
Onboarded sender domain; ≤50 recipients; ≤5 MiB; ≤32 attachments

Source: Email Workers runtime API, Send from Workers, Email Service limits.

Building on Email Workers yourself vs MarkRelay

Receive and route

Your own Worker
email() handler
MarkRelay
Included, catch-all or per address

Store messages and attachments

Your own Worker
You build it (D1, R2)
MarkRelay
Your D1 and R2

Inbox people can read

Your own Worker
You build it
MarkRelay
Multi-domain webmail with per-mailbox access

Send and reply

Your own Worker
send_email binding, reply()
MarkRelay
Webmail, HTTP API, MCP

Webhooks for new mail

Your own Worker
fetch() you write
MarkRelay
HMAC-SHA256 signed, scoped per mailbox

Unknown addresses

Your own Worker
Your logic
MarkRelay
Rejected at SMTP time

How MarkRelay uses Email Workers

MarkRelay deploys as a Worker into your Cloudflare account, and Email Routing hands it each domain's mail, through one catch-all rule or per-address rules. Before reading the message body, it checks the envelope recipient against your domains and mailboxes and rejects unknown or disabled addresses with setReject, so it never buffers mail it will not keep. Accepted mail is parsed and stored in your D1 database, with attachments in R2.

From there the Worker serves the webmail, the HTTP API and an MCP server, and posts a signed webhook for each new email to the endpoints scoped to that mailbox. Outgoing mail and replies go through Cloudflare Email Sending, so you get Email Workers' building blocks without writing the inbox around them.

Where MarkRelay fits

A good fit when

  • You want what an Email Worker can do, plus storage, an inbox and an API, without writing them.
  • Many addresses on a domain: one catch-all rule instead of up to 200 routing rules.

Look elsewhere when

  • Custom per-message logic in your own code: write your own Email Worker.
  • Sending above Cloudflare Email Sending's limits, such as more than 50 recipients in one message.

Common questions

Can an Email Worker forward to any address?

No. forward() delivers only to verified destination addresses.

How large can incoming mail be?

25 MiB; larger messages are rejected.

Sources and method

  1. Email Workers runtime API (developers.cloudflare.com/email-routing/email-workers/runtime-api/)
  2. Send from Workers (developers.cloudflare.com/email-service/api/send-emails/workers-api/)
  3. Email Service limits (developers.cloudflare.com/email-service/platform/limits/)
  4. Email Routing limits (developers.cloudflare.com/email-routing/limits/)
  5. Email Service overview (developers.cloudflare.com/email-service/)

Facts are taken from each vendor's own pricing pages, documentation or terms as of the updated date above; prices are in US dollars per month unless stated. Cost comparisons apply each vendor's published rates to the same volume. MarkRelay is not affiliated with Cloudflare;"site.developers.cloudflare.com" in the title names the site these facts come from. MarkRelay sells a self-hosted email app, which this page mentions where it fits. Spotted something outdated? Tell us.

Revisions

  • : First published; every fact checked on the vendor's own pages.

Related guides

More research