Introduction
Sending emails from applications has become a burden. If you try to set up your own server, chances are high that your IP gets blacklisted by some anti spam blacklister site. Some (most ?) of the hosters don’t even allow you to communicate on port 25. If you are not an expert of SPF, DKIM, and other DMARC configuration records on the DNS, and you just want to send some mails from an app, at the end of the day, you will prefer to rely some online SMTP relay services.
Those services are usually very complete: you can send simple mails that you craft yourself, or HTML templates designed by the platform. You can define web hooks that get called if the enduser clicks on your mail. You can also define campaigns to be send to many users, etc.. These platforms record everything about delivery and end user activity and you get the reports. Most of them have a “free tier” which allow you to send free emails with daily and monthly quotas.
This post reports my experience with few of them.
Requirements
My use case is very simple: I’m currently working on an a simple password less authentication library in Elixir. The user gives his email address and the library sends him one time access code. The user types the OTP in the interface and if the code matches the one that had been sent, he’s in.
The mails are to be send by a sender from domain my-domain.org, for
example, no-reply@my-domain.org.
Finally, whenever possible, I prefer to avoid US companies for privacy reasons.
Solutions
For sending the OTPs, there are several options:
Use your company’s internal email server:
This requires using SMTP directly and within the Erlang/Elixir ecosystem, you can use the gen_smtp library. Yet, direct SMTP might not be the most straightforward way as not everybody has access to the SMTP layer. Besides, your email server may be limited by quotas and your whole email infrastructure might be perturbed by some kind of anti-spam blacklisting. Finally, It’s never a good idea to use internal infrastructures for external usage.Use GMail:
While it’s possible to use the Google infrastructure to send mails with your domain, you have to have a paid Google account. For testing, there you can still use Google, but withgmail.comdomain. The configuration is said to be not so straightforward on many sites I have browsed (I didn’t try). Finally, GMail breaks my third requirement.Use SES service from AWS:
Same as GMail.Rent an SMTP mail server, often offshore:
It is probably the cheapest solution if you have really important volumes and the most secure as these companies operate from countries with specific jurisdictions. From technical point of view, they also often offer IP warm up and IP rotation to avoid black listing. However, just for testing, there is no free tier (remember, you rent a dedicated server…)Subscribe to a free SMTP relay service:
These services offer lots of facilities to handle emails: a simple HTTP API for sending, webhooks if the customer click somewhere, email templates, mailing campaigns, end-user activity reports and stats to name a few. The configuration of the service might sometimes be a bit tricky (some are trickier than others) as you need to modify your DNS configuration, but that will always be the case if you want your mails to be sent with a sender address that belongs to your domain.Often, these services are labeled as free SMTP servers: most (if not all) offer a free tier more or less generous, yet, none of them is totally free.
Sender’s domain authentication
When a server sends an email for a user from another domain, it’s called an “SMTP Relay”. If there is no authentication nor authorisation, its IP address gets blacklisted very, very quickly and then it’s hell difficult to unblacklist it. This costs reputation, time and IP availability to your ISP and this is usually why the ISP won’t allow you to communicate on port 25 with other servers.
There are two things to consider when a user wants to connect to a
server, say, relay.com and send an email in the name of
alice@sender.com to be delivered to bob@recipient.com:
Is this user allowed to submit an email for delivery to the relay? This is a matter of having the right credentials on
relay.com. ESMTP, the SMTP version in use today manage this very well and we’ll not get into this here.Is
relay.comallowed to send the email for the domainsender.com? There are three parameters that handle this part. All three are to be defined in the DNS zone of thesender.comdomain:- Sender Policy Framework, or SPF which defines who is allowed
to send emails on behalf of
sender.comdomain? - Domain Keys Identified Mail, or DKIM which insures that the email hasn’t been tampered with by cryptographically signing it
- Domain-based Message Authentication, Reporting and Conformance, or DMARC which tells what to do if SPF or DKIM fail
- Sender Policy Framework, or SPF which defines who is allowed
to send emails on behalf of
I’m not a specialist on this topic so for further information please see the references, but to configure our services properly we need to modify the corresponding fields in the DNS configuration. Before touching anything, the obviously good habit is to backup the whole DNS configuration. In my case, the documentation was really straightforward and both services we ready to operate with minutes.
Tested SMTP relay services
There are many surveys on the web for such services. For my tests, I have chosen just four of them.
Sendgrid
I’ve used Sendgrid few years back in my previous company. I don’t remember of any issue so I gave it a try even if it’s US-based. First, while I was able to login, I was surprised by a message saying that for security reasons my account had been closed and I was invited to create a new one. So, I created a new account, but I just could not manage to configure it properly and all the emails I’ve tried to send had been blocked. The documentation didn’t help.Probably I’m kind of dumb, but I remember one of my teachers at the university (long ago) who used to say If you don’t understand, it means I didn’t explain clearly enough. I apply this philosophy quite often to online services: if I don’t manage to use a service, probably the documentation is not good enough. So after a while I gave up with Sendgrid.
Mailjet
Mailjet used to be a French company and was acquired by the Swedish Sinch. Registration and configuration was straightforward. Yet, they require to “see” your app or webapp: my account was blocked and I had to provide an URL to my webapp and a description of the usage I was intending to do with the emails. I explained to an AI that it was just to send OTP codes. Then, the same to somebody I believe was human, but after some days of “review by Compliance team” I was informed that my application had been rejected.I quickly gave up with Mailjet.
Brevo
Brevo is a French company highly committed in sustainability (well, it’s important for me…) The free tier offers 300 emails daily. Configuration is straightforward and within 30mn I was able to send emails with cURL.Not much to say: it was a really good experience!
SMTP2GO
SMTP2GO is a company from New Zealand. According to some surveys, the service has among the best deliverability rates. The free tier offers 1000 emails per month. Less than Brevo, but more than sufficient for testing. Configuration was extremely simple: no modification of existing fields but just three new CNAMEs in the DNS. No risk to modify and introduce perturbations on production.Very good experience here too!
Both provide integrations with various languages; you can do your
first tests in shell with curl. However, personally, I’m an Elixir
fan, so…
Testing the services with Elixir and Swoosh
If you don’t know Elixir, you are really missing something…
Swoosh is Elixir’s native library to compose and send emails in a generic way, regardless of the backend service that actually makes the delivery. It supports the most popular transactional email providers out of the box and also has an SMTP adapter (documentation). Hopefully, it has adapters for Brevo and SMTP2GO.
The code snippet shows the
full source code of the send-email.exs script used for testing. To
make it work, we need to define the API keys as environment variables
then we can execute a test:
where:
-s <sender>provides the sender email address-p <provider>select the provider to be used,brevoorsmtp2go. This will also select the right environment variable that holds the API key,BREVO_API_KEYorSMTP2GO_API_KEY, and the adapter module Swoosh will use,Swoosh.Adapters.BrevoorSwoosh.Adapters.SMTP2GO.- follows a list of recipient’s email addresses (at least one)
The configuration of Swoosh is really simple. First we tell Swoosh
which HTTP client we’ll use, here req, and, second, we tell which is
the adapter module to be used with which API key.
1config: [
2 swoosh: [api_client: Swoosh.ApiClient.Req],
3 my_app: [{Mailer, adapter: adapter, api_key: api_key}]
4]
And this is more or less all we have to do
References
The SMTP library for Erlang/Elixir
Swoosh, the elixir library to Compose, deliver and test your emails easily
Mailgun - Email Authentication Basics. A gentle introduction
SPF. Kind of harder. Well, it’s an RFC…
DKIM. Same here.
DMARC. And same again.