After I migrated my website to blob storage via Azure CDN I accidently broke the MX record of my website and instead of fixing it like a normal person I decided to build my own email solution.
abused a free SendGrid account in combination with an azure function as my mail service:
- send/receive emails at your domain for free; no need to buy a mail package; assuming you stay within SendGrid limits (Azure also offers higher SendGrid limits)
- receive emails at any mailbox of the domain; forwarded to your preferred email address (and archived in blob storage if desired)
- attachments are parsed correctly (turned out to be not so easy) and are sent with the email
- respond to emails in the name of the domain
- send emails in the name of any domain email (including attachments)
Mainly I wanted to see if I could get rid of my 2$/month email service but still be able to send/receive emails from my domain.
Since I hardly ever send emails from my domain I was willing to accept a few shortcomings.
I was already familiar with SendGrid inbound parse thanks to a previous project so I figured I could throw together a quick PoC whether SendGrid can be used as a free email service.
A few hours later the answer was yes.
I polished the project and published it on github so others can use it as well.
Note that more professional solutions exist as well (such as ImprovMX) however from what I have seen they all require you to enter your email password into their service (giving them theoretically full access to your private email.
The way my email function works, it only needs access to your domain email (via SendGrid) but not your private email.
And since you have to deploy the Azure function yourself (for pennies a month) I (personally) don’t get access to any of your mails.
How it works
Under the hood an azure function is used to receive SendGrid Inbound Parse events. They are fired by SendGrid for every incoming email.
The azure function then parses the email and forwards it to you own private email.
Since there is no concept of mail storage at the domain (SendGrid only forwards it) the mails can optionally be archived in azure blob storage as well (although the forwarded emails will already be stored in your private email account and that’s good enough for me).
After you set it all up you can use it to send/receive emails.
Receive an email
The subject will let you know who actually sent it while the sender is the alias from your domain that originally received the email (this seems clunky but is the only way to get the email to your private inbox).
Responding to emails
When you respond to such an email you essentially respond to email@example.com. The azure function will parse the email again, realize it is coming from your configured private email and then transform the subject and send it to the correct address in the name of the domain.
The subject format “Email relay for: <email>” will be parsed and result in an email from firstname.lastname@example.org to be sent.
Sending an email
To send a new email in the name of the domain you need to send an email from your registered private email to the domain (the azure function will realize it’s you and relay the email).
To send an email “Test subject” from email@example.com to firstname.lastname@example.org you must send an email with subject “Email relay for: email@example.com: Test subject” to firstname.lastname@example.org.
The special subject and the fact that the sender is your registered email will let the azure function know that it should send an email from the domain to the target.
There are a few problems I am aware of (listed on github as well) so check if those are deal breakers for you:
- CC/BCC are lost for relayed emails (but are visible in the blob storage if enabled)
- inline content is currently not supported (all media will be sent as regular attachments)
- Reply all/to multiple doesn’t work, as each email goes through your domain, so only one recipient at a time is possible
- you can only use one email account as the sender/recipient for all emails (set via EmailRelayTarget)
- you can only use one domain per function (e.g. if you want to receive mails for example.com and mail.example.com you have to setup two functions)
- attachment names with non ascii characters are wrongly encoded if sent via SendGrid (the content is always correctly encoded, though). This is an issue with SendGrid
Setup & more examples
The entire function is opensource on github including a setup guide and more examples.