How to self-host agent email on Cloudflare
Build the mailbox application in your own account, then validate compute, state, DNS, inbound routing, outbound delivery, and agent access as separate layers.
To self-host mails0, deploy the Worker, bind a D1 database and R2 bucket, apply the current schema, configure secrets, route inbound mail from a dedicated Cloudflare Email Routing subdomain, and connect a verified outbound sender provider. Then create a scoped mailbox and prove one external inbound and outbound workflow before production use.
Workflow at a glance
Deploy in an order that preserves evidence
- 01Review configuration and schema
Confirm the target Worker, D1 database ID, R2 binding, environment variables, and migrations before any remote command.
- 02Apply resources locally first
Run schema and route tests against local or disposable resources and verify auth and scope behavior.
- 03Create remote bindings and secrets
Provision D1 and R2, store secrets with Cloudflare, and deploy the Worker without committing credentials.
- 04Configure inbound Email Routing
Attach the intended address pattern or subdomain to the Email Worker and preserve existing MX responsibilities.
Prepare ownership before deployment commands
You need a Cloudflare account, a domain you can configure, a reviewed checkout of the mails0 repository, and an outbound sender provider if the deployment will send. Use a dedicated inbound subdomain when the root domain already serves human email.
Decide who owns secrets, migrations, incident response, retention, and upgrades. A successful one-time deploy is not a production operating model.
- Cloudflare account and Wrangler authentication.
- Domain or subdomain for agent mail.
- D1 and R2 resource names and environments.
- Outbound provider domain verification and webhook secret.
- Backup, retention, monitoring, and abuse-control decisions.
Deploy in an order that preserves evidence
-
01
Review configuration and schema
Confirm the target Worker, D1 database ID, R2 binding, environment variables, and migrations before any remote command.
-
02
Apply resources locally first
Run schema and route tests against local or disposable resources and verify auth and scope behavior.
-
03
Create remote bindings and secrets
Provision D1 and R2, store secrets with Cloudflare, and deploy the Worker without committing credentials.
-
04
Configure inbound Email Routing
Attach the intended address pattern or subdomain to the Email Worker and preserve existing MX responsibilities.
-
05
Configure outbound delivery
Verify sender DNS and connect the supported provider; treat provider acceptance and recipient delivery separately.
-
06
Run bounded production checks
Verify health, one scoped mailbox, external inbound receipt, retrieval, and only then an approved outbound message.
Harden identity, rate limits, and data before onboarding agents
Mailbox systems attract abuse because addresses and outbound delivery are valuable capabilities. Keep permanent mailbox creation, domain administration, and operator scope away from anonymous agent flows.
Provisional identities should expire, remain receive-only, and be rate-limited by privacy-preserving principals. Authentication failures, global capacity, per-mailbox sending, and claim creation need explicit controls and observable failures.
- Hash network and token identifiers before analytics or rate-limit storage.
- Keep raw message bodies and secrets out of general logs.
- Verify webhook signatures and process retries idempotently.
- Separate operator, permanent mailbox, and provisional token scopes.
- Schedule cleanup for expired provisional identities and short-lived claim data.
Prove every production layer separately
| Layer | Evidence | What it does not prove |
|---|---|---|
| Worker deployment | Version and healthy API response. | DNS routing or email delivery. |
| D1 schema | Expected tables, columns, and read/write test. | Message routing or provider callbacks. |
| Inbound routing | External message stored and retrievable. | Outbound domain reputation or delivery. |
| Outbound provider | Provider accepts and reports state. | Recipient inbox placement. |
| Agent interface | CLI, SDK, or MCP reaches scoped mailbox. | Business authorization for every action. |
Plan the second month, not only the first hour
Monitor usage, storage, error rates, delivery states, failed authentication, paused accounts, and abuse cohorts without collecting message bodies or raw keys. Test restore and migration procedures before an incident requires them.
Track which version of the Worker, CLI, Python package, and MCP server each environment uses. A production system can drift even when the public documentation looks current.
Prove inbound and outbound as two independent systems
After deployment, send a message from an external provider and confirm the Worker, D1 metadata, R2 object, mailbox API, and retrieval client all agree on the same message identity. Then test outbound separately through the configured sender provider and record acceptance and delivery status without assuming one proves the other. Add alarms for route failures, storage errors, quota pressure, and sender problems. A production readiness review should also cover data deletion, key rotation, migration rollback, domain recovery, dependency updates, and who can pause the service during an incident.
Sources and product scope
Product behavior is verified against the mails0 source and documentation. External comparisons link to official vendor documentation checked on 2026-08-15.
- mails0 source repositoryImplementation, license, and deployment source
- mails0 self-hosting documentationCurrent repository deployment steps
- Cloudflare Email ServiceOfficial routing documentation
Questions that come up in practice
Can I deploy mails0 on a Cloudflare subdomain?
Yes. A dedicated mail subdomain is usually recommended when your root domain already has an email provider.
Does self-hosting remove the need for an email provider?
No. Cloudflare Email Routing handles inbound mail. Configure a supported verified sender provider for outbound delivery.
What data belongs in D1 versus R2?
Use D1 for mailbox and message metadata that must be queried. Use R2 for raw MIME and attachment payloads that should be retrieved explicitly.
How do I know the deployment is production-ready?
Local tests, deploy success, schema health, inbound routing, outbound provider state, and agent access are separate gates. Add monitoring, retention, backup, and abuse-response evidence before calling it production-ready.
Give the agent an inbox, then prove the workflow.
Start with a receive-only temporary mailbox. Move to a permanent identity or self-hosted deployment only after the workflow reaches a real email value event.