Email Freedom: A Zero-Cost, Maintenance-Free Private Mailbox That Keeps Your Address When You Switch Providers
· 15 min read
Digital LifeThe first rule of tinkering with routers, NAS boxes and edge computing: you own a domain. And once you have a domain, a private mailbox on it is the obvious next step. I’ve tried hosted business mailboxes before. Storage is limited, spam filtering is mediocre, and the space runs out sooner than you’d expect. The big international options, Google Workspace and Microsoft 365, bill per seat, which gets expensive for a one-person company or a home lab. On top of that, your mailbox ends up tied to the vendor’s admin console and account system, which is a hassle.
But a private mailbox doesn’t have to mean paying for a business mailbox. After some tinkering I settled on Cloudflare Email Routing, for practical reasons:
• My domain is already here. My domains, my blog and a lot of other services live on Cloudflare. Email Routing can write the MX, SPF and DKIM records for you in one click, so there’s no more copying values out of the documentation by hand. Very convenient.
• No storage or seat worries. Email Routing only forwards. Your mail stays in your own mailbox, so storage is whatever that mailbox gives you. Receiving is free and unlimited, and there’s no per-account fee.
• As many addresses as you like. With a catch-all and a few rules, throwaway signup addresses, blocking and spam filtering are all yours to control.
• No platform account to bind. You don’t have to sign up for yet another vendor’s console, or verify a pile of business details, just to own a mailbox.
Setup
The only prerequisite for Email Routing is that your domain’s DNS is served by Cloudflare. Email Routing itself is free and receiving is unlimited, so let’s get the foundation right first.
Put your domain on Cloudflare
It doesn’t matter where you bought the domain. Namecheap, GoDaddy, Squarespace, IONOS or Cloudflare Registrar all work. What matters is switching the nameservers (NS) to the pair Cloudflare assigns you.
1. Sign in to Cloudflare, choose Add a domain in the dashboard, enter your root domain (for example example.com) and pick the Free plan.
2. Cloudflare scans your existing DNS records. Check them one by one: add what’s missing and remove what’s stale, especially the A / CNAME records, so nothing breaks when resolution switches over.
3. The page gives you two nameservers (something like xxx.ns.cloudflare.com). Go back to your registrar, replace all the existing nameservers with these two, and don’t mix them with the old ones.
4. Back in Cloudflare, run the check and wait for the domain status to change from Pending to Active. It usually takes a few minutes. Some registrars are slower, but it rarely takes more than 24 hours.
A few pitfalls:
• Turn off DNSSEC first. If DNSSEC is enabled at your registrar (there is a DS record), disable it and wait for the change to take effect before switching nameservers. Otherwise resolution fails and the domain stays Pending. You can turn DNSSEC back on in Cloudflare afterwards.
• Don’t preset the nameservers. Add the domain in Cloudflare first, then copy the nameservers it assigns to your registrar. Nameservers you preset beforehand get replaced by the newly assigned ones.
• If you used to host mail on this domain with Google Workspace, Microsoft 365 or Zoho, don’t delete the old MX records yet. Deal with them right before you enable Email Routing.
Enable Email Routing
Once the domain is Active, open Compute → Email Service → Email Routing in the dashboard and select your domain to enable it. If the menu looks different on your side, just search for “Email Routing” in the dashboard.
When you enable it, Cloudflare adds three kinds of DNS records for you. You don’t have to type any of them in:
| Record | Purpose | Notes |
|---|---|---|
| MX | Sends mail addressed to your domain to Cloudflare first | Points to Cloudflare’s mail servers, usually several records |
| TXT (SPF) | Declares which servers may send on behalf of your domain | An existing SPF record is not overwritten; you add Cloudflare’s include: by hand |
| TXT (DKIM) | Used for signature verification | Host name looks like cf2024-1._domainkey |
If the domain still has old MX records from Google Workspace, Microsoft 365 or Zoho, enabling fails with error 2008 (non-Cloudflare MX records exist). The order of operations matters:
1. Verify your destination mailbox first (see the next section). Destination addresses belong to the account, so you can add them in advance.
2. Go to DNS → Records and delete the old provider’s MX records.
3. Enable Email Routing right away so Cloudflare writes the new MX records. There’s a short gap between the two steps, but most sending servers retry, so you shouldn’t lose mail.
4. Create your routing rules immediately. Once the MX records point to Cloudflare, mail to an address with no matching rule is bounced as “address does not exist”, and the sender won’t retry.
If you still send through the old provider, keep its SPF include: and DKIM records. If you’re done with it, clean them up too. Don’t cancel the old mailbox during the migration, in case some senders have cached the old MX records and keep delivering there for a while.
Verify your destination mailbox
Cloudflare doesn’t provide mailbox storage. It only forwards mail sent to your domain to a real mailbox you already use, which Cloudflare calls a destination address. That’s also why storage stops being an issue: the mail lives in your own mailbox and that provider decides how much space you get. If the destination mailbox runs low on space, you can switch to another one.
1. Open Email Routing → Destination addresses.
2. Enter the mailbox you actually read and submit it. Any mailbox you actually read works, and Gmail is a common free choice.
3. Open that mailbox, find the verification email from Cloudflare and click Verify email address.
4. Back on the page, the address should now show as verified.
A few notes:
• An unverified address can’t be used in routing rules, and rules pointing to it stay disabled. If the verification email doesn’t arrive, check your spam folder first, then resend it from the list.
• Destination addresses belong to your Cloudflare account, not to a single domain. Verify one once and reuse it for every domain in the account.
• You can have up to 200 destination addresses per account, which is plenty for personal use or a small team. To route mail to family members or staff, verify their real mailboxes the same way.
Create custom addresses
A private address is simply a routing rule of the form “matching address → destination address”. The moment you create it, the address can receive mail. There’s no separate “account” to set up.
1. Open Email Routing → Routing rules and click Create routing rule.
2. In Email pattern, enter a prefix and choose the domain. For example, prefix hello and domain example.com give you hello [at] example [dot] com.
3. Set Action to Send to an email and choose the mailbox you verified in the previous section.
4. Save, then send a test message to hello [at] example [dot] com from another mailbox. It should reach your destination mailbox within seconds to a few minutes.
5. Naming business and personal addresses separately keeps things tidy. Each domain can have up to 200 routing rules, which you’ll hardly ever use up.
6. To give a subdomain such as corp.example.com its own mailboxes, add it under Settings → Subdomains in Email Routing. Subdomains don’t support the catch-all, so you create rules one by one.
Cloudflare also supports + sub-addressing, just like Gmail: mail sent to hello+shop [at] example [dot] com falls back to the rule for hello@. Add a suffix whenever you sign up somewhere, and you’ll see it on the incoming mail and can filter your inbox by it to tell where a message came from.
Set up routing rules
Routing boils down to one sentence: match the recipient address against a rule, then run an action. Email Routing has these built-in actions:
| Action | Effect | Good for |
|---|---|---|
| Send to an email | Forwards to a verified real mailbox | Everyday mail |
| Send to a Worker | Hands the message to a custom Worker in the same account | Advanced scenarios where you write the code yourself |
| Drop | Silently discards the message; the sender gets no bounce | Addresses you never want to hear from again |
This is what happens to an incoming message: the sending server delivers it to Cloudflare, which runs SPF, DKIM and DMARC checks (mail that fails the sender domain’s DMARC policy is rejected), matches the recipient against your rules, and runs the action. When forwarding, Cloudflare rewrites the envelope sender (SRS) so the destination mailbox doesn’t treat the forwarded message as forged.
To turn on the catch-all:
1. Open Email Routing → Routing rules.
2. Find the Catch-all rule and switch it on, so it shows Active.
3. Set Action to Send to an email and click Save.
The catch-all forwards mail sent to any address on your domain, including misspelled prefixes. In terms of order, the specific addresses you created explicitly win, and the catch-all only applies when no rule matches.
One caveat: a rule can only point to a single destination. To send different addresses to different mailboxes, create separate rules. Delivering one message to several mailboxes at once isn’t possible with the built-in options, but you can do it with a Worker.
Rules can be edited, disabled or deleted at any time. If you just want to stop receiving mail at an address for a while, disable its rule instead of deleting it.
Send mail
Email Routing only handles incoming mail. To send from an address like hello [at] example [dot] com, use a transactional email service such as Brevo or Resend. Receiving and sending are set up separately, so your destination mailbox can be any mailbox you like.
Menu names change from time to time, so I describe features rather than exact labels. Go by what you actually see in your settings, and send yourself a few test messages once it’s set up.
Sending with a transactional email service (Brevo, Resend and similar)
1. Sign up with a provider. Brevo allows 300 emails a day and Resend 3,000 a month (capped at 100 a day). Brevo reviews new accounts before they can send.
2. Add a sending domain. Use a subdomain such as mail.example.com rather than the root domain: MX records on the root domain would conflict with Email Routing.
3. The provider lists the DNS records you need (ownership verification, SPF, DKIM and so on). Add them one by one on Cloudflare’s DNS page, all set to DNS only, then go back and verify.
4. Create a sender address (for example hello [at] mail [dot] example [dot] com) and SMTP credentials.
5. Configure SMTP in a client such as Thunderbird or Apple Mail, or in your web app. Resend uses smtp.resend.com on port 587 with the username resend and an API key as the password. Brevo uses smtp-relay.brevo.com on port 587 with your account email and an SMTP key. To have replies come back to your private address, set Reply-To to hello [at] example [dot] com. Replies then go through Cloudflare into your destination mailbox.
A few things to know before you send:
• The message is actually sent by the provider’s servers, so some clients, such as Outlook, may show an “on behalf of” or “via” notice. Your domain can have only one SPF record, so merge any include the provider asks for into it, next to Cloudflare’s, for example v=spf1 include:_spf.mx.cloudflare.net include:provider.example ~all, and take the exact values from the provider’s docs.
• If your domain has a strict DMARC policy (for example p=reject), sent mail may be rejected when the sending domain doesn’t align. While you’re using this setup personally, keep DMARC lenient (p=none), watch deliverability for a while, and tighten it later.
• Big mailbox providers like Gmail, Outlook and Yahoo are stricter with new domains and first-time senders, so your first few messages may land in spam. Ask recipients to add your address to their contacts and exchange a few normal messages, and delivery settles down over time.
Cloudflare also has its own Email Sending feature (Compute → Email Service → Email Sending). When I checked, it sends through a REST API or a Worker rather than SMTP, so it doesn’t fit a mail-app workflow. Check its current docs in case that changes.
In practice
The biggest change after setting this up is freedom: addresses are no longer scarce and storage is no longer something to worry about. These are the three ways I actually use it day to day.
Throwaway addresses for signups
With the catch-all on, your domain has unlimited addresses. For every site or service you sign up to, just make up a unique prefix on the spot. You don’t have to create it in advance:
• cloudvendor [at] example [dot] com for a cloud service
• forum-2026 [at] example [dot] com for a forum
• x7k2q [at] example [dot] com for a one-off verification
All of these land in the same real inbox, so verification codes and activation links arrive as usual. There are three benefits:
1. You can trace leaks. If a site is breached or a service sells your address, the prefix tells you who it was.
2. You stay in control. When one prefix starts attracting junk, give it its own reject rule and you’re done, without touching any other address.
3. Your main mailbox stays private. Public signups use a throwaway, so your real address never ends up in someone else’s database.
I suggest a consistent “service name + random string” format, ideally generated by your password manager, with one address per site.
Accepting or rejecting by address
After a while some throwaway addresses will inevitably get scraped or sold to advertisers. That’s where per-address routing comes in: you give different addresses different treatment.
1. Accept into specific mailboxes
Create a separate rule for each purpose and point it at a different real mailbox. For example, billing@ goes to your finance mailbox, admin@ to your own work mailbox and support@ to a partner. As long as each destination is verified, one domain can handle inbound mail for a small team.
2. Reject specific addresses
There are two ways to do it, and the results differ:
| Method | What the sender sees | Best for |
|---|---|---|
| Give the address its own rule, action set to Drop | Nothing; the message is silently discarded | Ad-only addresses you never want to see |
| Turn off the catch-all and keep only the addresses you need | A bounce saying the address doesn’t exist | Once your addresses have settled and you no longer invent throwaway ones |
Rejecting one address: In Routing rules, add the address you want to reject, set the action to Drop and save. A specific address rule takes priority over the catch-all, so that prefix is dropped even while the catch-all is still on.
Tightening with an allowlist mindset: Once your regular addresses have settled, turn the catch-all off and keep only the addresses you’ve created rules for. Mail to any other address is bounced, so only addresses you’ve approved can reach you. It’s a different stance from the throwaway addresses above: catch-all on is the most freedom, catch-all off is the cleanest inbox, and you can switch between the two as your needs change.
Filtering spam
Junk mail goes through several checks built into Email Routing before it reaches your inbox. Some are fully automatic and some take a few clicks in the dashboard. None of them needs code.
1. Sender authentication (automatic). For every incoming message Cloudflare checks SPF, DKIM and DMARC. Mail that fails, from a domain whose DMARC policy asks for rejection, is refused at this stage and never reaches your rules. Plenty of forged-sender spam gets stopped right here.
2. Real-time blocklists (automatic). Deliveries from IP addresses on known spam blocklists are rejected.
3. Address-level control (you set it). Give a harassed address a rule that drops its mail.
4. Your destination mailbox’s own spam filter. Once the mail is forwarded to Gmail, it still goes through Gmail’s spam filter. Keep it on, and manage your block and allow lists in Gmail’s settings.
Going further: more tricks
The built-in rules cover everyday needs, but they can only match on the recipient address. If you’re willing to invest a bit more in setup and upkeep, there are finer-grained options. The effect looks like this:
• Bounces with a reason. Retired addresses are no longer silently discarded. The sender gets a bounce saying the address is no longer in use, so legitimate senders can clean their lists.
• Bulk blocklist management. All retired prefixes live in one list. Adding one means adding a single entry, instead of creating a rule in the dashboard each time.
• Allowlist and catch-all together. Keep the freedom of inventing throwaway addresses, yet let through only the addresses you’ve approved and bounce the rest.
• Filtering by sender quality. Mail whose sender address lacks an @, has an incomplete domain or is empty is stopped on the spot, with a record kept for later review. This catches junk that passed authentication but still looks suspicious.
• One message to several mailboxes, plus auto-replies and keyword-based sorting or archiving.
• Fully private-address sending. Replies and new messages both go out showing only your own-domain address (for example hello [at] example [dot] com) as the sender, with no trace of a third-party sending service and no “on behalf of” notices. Replies automatically use the address the message was received at, and deliverability is steadier.
Most of these are built on Workers and need extra setup and upkeep. If you’re interested, leave a comment and let’s talk about it.
Wrap-up and limitations
Receiving goes through Cloudflare Email Routing, everything lands in your own mailbox, and sending borrows a mail service. Receiving is completely free: it’s unlimited, you can create as many addresses as you like, and you’re no longer boxed in by one mailbox vendor’s storage and account rules. The price is that Email Routing is essentially a forwarder, so keep these limitations in mind:
• Receive only. Email Routing doesn’t send. Sending relies on a transactional email service. Any mailbox can be the destination.
• 25 MiB per message. Larger messages are rejected at delivery. Share big attachments as links from a file-sharing or object storage service.
• There are quantity limits. 200 routing rules per domain and 200 destination addresses per account.
• There’s no webmail. Mail actually lands in your destination mailbox, where you read, archive, search and send. If you later want to change the destination mailbox, just change the destination address in the rules.