How to host email for custom domains for free (or almost free)


There are many options for hosting email for custom domains cheaply these days; one of such services is Zoho which I have used for the past several months after Google Workspace, Fastmail and even self hosted email with Mailcow on Docker. Zoho is a pretty good service and it's very cheap, but anyway if you have several custom domains the cost adds up.
Since I am cutting costs with my subscriptions, I was looking for a cheaper way to host email for several domains. I came across the Cloudflare Email Routing service and I decided to give it a try.
Cloudflare's service does not host your email, but it allows you to create forwarding routes to route any incoming email to your custom domain to existing email addresses you already have. This means that I can receive emails sent to [email protected] in an existing inbox. In my case I am using free Gmail accounts for this.
So Cloudflare handles receiving emails, Gmail (or other free email hosting service) handled storing them for me, what about sending emails from a custom domain with this setup?
For this you have two options. The simplest is to just use Gmail's own SMTP servers to send emails as if they were sent from your custom domain. The downside of this is that some email clients will show some banner saying "sent via gmail.com" or something like that next to the sender address, so you may not like that.
A better option is to use an SMTP relay. For this, we can use any service that operates the delivery of transactional email. These services are usually used to send automated emails from applications, such as confirmation emails on sign up, password recovery emails and the like, but they can work just fine for our purpose too.
If you want to cut the email hosting costs completely to zero there are some of such providers who have a free tier. For example, Mailjet allows you to send up to 200 emails per day from your custom domains; I think Sendinblue has an even more generous free tier. Personally I opted for ZeptoMail, a competitor from Zoho. I need to pay a minimum of 2.50 euros per credit, but each credit lasts 6 months and allows sending up to a whopping 10K emails. So it's not completely free but it's so cheap and with much higher limits, so I went with this one.
Setting up email routing in Cloudflare
In this post I'll assume you are able to create an account with Cloudflare, and migrate your domains to it for the DNS part. It's a very easy process and completely guided, so I am not going into how to do that here.
Once the domain is migrated to Cloudflare, select "Email" from the sidebar:

If the domain was previously configured to accept incoming email, it will already have one or more MX records, so you will see a screen similar to this:

If that's the case, go first to the DNS settings for the domain, delete the existing MX records, then come back to the email settings and click Add records and enable. In a short time you should see a confirmation that the DNS is configured:

You can ignore the "3 Destination addresses" here. It's because I had already configured some before configuring the domain in these pictures. Next, click on Routes, then Add destination address, and enter the email address you want incoming email for your custom domain to be forwarded to. This can be a Gmail address or any other free email service.
Cloudflare will send an email to the target address with a link to confirm it. Click on it, then once verified/confirmed go to the Routes panel again, and click Create address:

Enter the username for the email for the custom domain (dynablogger.com in this example), as well as the target address. As soon as the MX records are propagated, any incoming email sent to [email protected] will be forwarded to the target address.
Sending emails as from the custom domain
In Gmail, go to Settings > Accounts and Import and click on Add another email address under Send email as.

Enter your display name as well as the email address for the custom domain (that you want to send emails as), and in the next step configure the SMTP server:

For Gmail, the host is smtp.gmail.com and of course you need to use your email and password. If you have 2FA activated on your Gmail account, you'll need to use an app specific password instead.
You also need to ensure Google's servers are allowed to send emails for your custom domain. So head to the DNS settings in Cloudflare, and edit the TXT record with the word spf in the content. You need to change it to the following value:
v=spf1 include:_spf.mx.cloudflare.net include:_spf.google.com ~all
Save and a wait a little while. From now on, emails send from Gmail using the alias will use Google's server to deliver the email but the email will appear as coming from the custom domain.
There's a little problem though. While this works great, some email clients will notice that the emails coming from your domain were actually sent from servers for another domain (Gmail's), and therefore will show a banner saying "sent via gmail.com" or similar next to your email address. Like I mentioned earlier, you can avoid this by using a provider for transactional email delivery configured to send emails from your custom domain correctly. Each provider's control panel will look different but the process is the same and typically involves creating a TXT DNS record for DKIM authentication, as well as adding the provider's servers to your SPF configuration. Some provider may take a couple of days to review your account to ensure you are not going to use them to send spam around.
Migrating existing emails
brew install imapsync
on macOS but may require more steps for other operating systems. Check the docs for details on how to install.
Once installed, you can migrate emails from the old hosting service to the new one with the following command:
imapsync --host1 imappro.zoho.eu --ssl1 --port1 993 --user1 "email@customdomain" --password1 "...." --host2 imap.gmail.com --ssl2 --port2 993 --user2 "[email protected]" --password2 "..."
Host1 is the source host (replace Zoho's IMAP server with the correct one for your previous provider), while host2 is the IMAP server for the free email account you will be using for storage. The migration will take quite a while, especially if you have many emails in the existing account, but the process shows a useful ETA while migrating so you know how long it's gonna roughly take.