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
- 1email(message, env, ctx) receives from, to, headers, raw, rawSize and canBeForwarded.
- 2setReject(reason) rejects with a permanent SMTP error; forward() delivers only to verified destination addresses and keeps only X- headers you add.
- 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.
- 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.
- 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
| Method or property | What it does | Rules |
|---|---|---|
| from, to, headers, raw, rawSize | Envelope, headers, raw MIME stream, size | Read-only |
| setReject(reason) | Rejects with a permanent SMTP error | Not stated |
| forward(rcptTo, headers?) | Delivers to another address | Verified destinations only; only X- headers can be added |
| reply(message) | Threaded reply to the sender | Once per message; to the sender; from the receiving domain; valid DMARC; ≤100 References |
| send_email binding | Sends new mail | Onboarded sender domain; ≤50 recipients; ≤5 MiB; ≤32 attachments |
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
| Piece | Your own Worker | MarkRelay$99/yr + Cloudflare |
|---|---|---|
| Receive and route | email() handler | Included, catch-all or per address |
| Store messages and attachments | You build it (D1, R2) | Your D1 and R2 |
| Inbox people can read | You build it | Multi-domain webmail with per-mailbox access |
| Send and reply | send_email binding, reply() | Webmail, HTTP API, MCP |
| Webhooks for new mail | fetch() you write | HMAC-SHA256 signed, scoped per mailbox |
| Unknown addresses | Your logic | Rejected at SMTP time |
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
- Email Workers runtime API (developers.cloudflare.com/email-routing/email-workers/runtime-api/)
- Send from Workers (developers.cloudflare.com/email-service/api/send-emails/workers-api/)
- Email Service limits (developers.cloudflare.com/email-service/platform/limits/)
- Email Routing limits (developers.cloudflare.com/email-routing/limits/)
- 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
- Email Routing and Sendingsite.cloudflare.com Email Routing: free custom domain email, and how to send
- Email Routing and Sendingsite.cloudflare.com: the DNS records for Email Routing and Email Sending
- Transactional emailsite.resend.com pricing: free plan, 3,000 emails and 100 a day
- Email marketing and SMTPsite.brevo.com pricing: free plan, 300 emails a day
- Custom domain emailsite.zoho.com Mail pricing: free plan for 5 users, and Mail Lite at $1
- Custom domain emailsite.fastmail.com pricing: custom domain email from $5 a month