has_many :codes

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


Update July 27, 2022: I have read quite a bit on the risks of this kind of setup potentially affecting the reputation of your custom domains, so I feel obliged to leave a note about it. Emails forwarded by Cloudflare the way I describe in this post are seen by clients as "mailed by" my own custom domain. The problem with that is that if I flag an email I have received that way as spam, Google sees that the email was sent by my domain and therefore the action might affect the reputation of my domain. I couldn't find a conclusive confirmation if that's the case / if it's an actual problem, but to be honest I don't want to risk at this stage so I decided to stick with paid email hosting for my domains for the time being. Only difference is that I went with MX Route instead of Zoho this time.

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

The first thing you'll need to do is enable email routing for your domain(s) and create one or more forwarding routes. This requires, unfortunately, that you use Cloudflare to host the DNS configuration for your domains, but there are plenty of good reasons why you would want to do that anyway these days (if you are not familiar with the service, I recommend you take a look at their website to see all the features they have to offer besides DNS. Cloudflare is also wildly popular as CDN.

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

So far we are able to receive incoming emails for the custom domain to some free email accounts such as Gmail. However, any emails sent from the Gmail/etc account will be seen by the receiver as coming from Google, not our custom domain. To fix this, we need to configure Gmail or equivalent to send emails as if from the custom domain address. We need to create an alias basically. I'll show here how to do it with Gmail, but the process will be very similar with other providers.

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

If you were using the custom domain with email already before configuring Cloudflare routing, you may want to migrate all your past emails to the free Gmail/etc account you will now be using for storage. There's a nice tool for that called imapsync. Installing it is as simple as 

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.

Configuring email clients

If you use a desktop/mobile app for emails instead of the browser, I recommend you configure the accounts as custom IMAP accounts even if for storage you use something like Gmail that can be configured more automatically. This is because this way you can use the Gmail address for authentication with the storage account, while using the custom domain address as sender address, and you can also configure the correct SMTP server. An alternative is to configure aliases instead, but not all clients support that. 


Like I mentioned in the beginning I am trying to cut costs with my paid subscriptions, so I was happy to see how well this solution works. It's easy to set up and it can cost literally zero if you use a free plan for the transactional email delivery. So if you host a few domains and want to save some bucks every month, it's an option worth considering. Let me know in the comments if you run into any issues with the setup and I'll be happy to help if I can.
© Vito Botta