The first will say “No, don’t do it! It’s a virtually impossible thing to do these days!”
The second will say “Don’t listen to that guy! It’s trivial! I just installed one and I had no problems!”
Both are right, and both are wrong: It’s very much possible to run your own MTA (Mail Transport Agent), but there’s a lot of steps required if this is to be successful (where “successful” is here defined as “Gmail won’t put your email in the spam folder”). Every one of these steps are trivial, but you have to suffer through many TLA and ETLA concepts that there’s really no point in knowing anything about.
I mean, just to run a mail server.
So I’ve written a script that does it all for you. Other than the DNS changes that you’ll have to do, but it’ll tell you exactly what you have to put where.
The script requires a Debian or Ubuntu host, and it’ll install a whole lot of stuff. If you already have a partial mail server setup, it may break the server. Nothing’s guaranteed.
After running it, you’ll have a host with (ETLAs incoming) the exim4 SMTP server (with TLS, DKIM signing, ClamAV and Spamassassin), Dovecot IMAP (with TLS), SPF, DMARC and certificates from Let’s Encrypt.
If you’re a spammer (I mean “marketing expert”), please go away. This is not about being able to send out newsletters; it’s for people who want to run their own mail servers for whatever reason (for instance, to avoid the monoculture of Gmail).
tl;dr:
Download the script
curl -O https://raw.githubusercontent.com/larsmagne/make-mta/master/make-mta.sh
and then run it. Follow the instructions, and you’re done.
Longer version:
Running a mail server doesn’t take much work: After it’s up it, it’s probably going to stay up. However, I’m going to go through all through all the steps the script does, so that if you’re interested you can understand how it all fits together.
This is going to be overly detailed: I’m going to go through everything, point by point, from provisioning a server to configuring your mail client. Prepare to scroll.
The assumptions are: You own a domain, and you want to send out mail from that domain, and you want to receive mail for that domain. In my case, I have the domain “eyesore.no”, and I’ll be using that throughout all the examples.
First of all, you need a name for the server. “mta” is nice, so I’ll call mine “mta.eyesore.no”. Now that the difficult part is over (“there’s only two difficult things in IT: Naming, caching and off-by-one errors”), you need a server.
Any hosting provider is fine: Let’s go with DigitalOcean. After you’ve gotten an account there, click “New Project”, give it a name, and then “Create”.
Create a Ubuntu LTS image; the cheapest one they have. An MTA requires virtually no resources, but if you expect to keep a lot of incoming mail on your IMAP server, you may want one with more storage than 25GB.
These days, it’s nice to have IPv6 support, but it doesn’t really matter much.
You need a way to log in. I strongly recommend adding your public ssh key here, but you can also use a password.
And here’s where you enter that name you came up with earlier.
Then create the server (or “droplet” as DigitalOcean cutesely calls it).
Within a few seconds, your server is created, and that number is the IPv4 address of the server (and the unhelpfully shortened IPv6 address).
Now go to your DNS provider (and you’ll be doing a lot of things here, so keep this window open) and add some resolving.
I’m using Cloudflare, because it’s… nice?
That’s an “A” record for the IPv4 address…
… and an AAAA record for IPv6.
Now you can ssh to the server:
Download the script
curl -O https://raw.githubusercontent.com/larsmagne/make-mta/master/make-mta.sh
and then run it:
This will do basic stuff like “apt upgrade”. Nice to have the system somewhat up-to-date.
This will install and enable the ufw firewall, and open the ports we need to run an MTA (ssh, smtp, imaps, http). fail2ban is also installed.
The script will then try to figure out the host name based on the IP address. If it can’t, then it means that reverse DNS wasn’t added automatically, and you have to add a PTR DNS record for the IP address (both IPv4 and IPv6, if you have that). All MTAs need to have reverse IP records, otherwise many MTAs will refuse to accept mail from the server.
This will start a standalone http server and use the Let’s Encrypt servers to acquire a TLS certificate. Answer the questions it asks.
Next, it’ll fetch and configure exim itself (along with SpamAssassin and clamav), and set up DKIM. (DKIM is a way to sign mail so that others can verify that it comes from your mail server.)
This server accepts mail for you, so you need a way to read it. IMAP is the preferred way for most. This IMAP server will also use the Let’s Encrypt certificates to authenticate the connection.
We’re done! That is, we only have to make these DNS changes that the script has summarised. So let’s do them, one by one, in the Cloudflare interface.
First, the DKIM public key. This will allow other MTAs to verify that an email came from this MTA.
Then the SPF data. This says that your MTA is allowed to send mail from your domain.
Then the DMARC data. This says that you should do with failures from DKIM and SPF. (Note that this DMARC policy is very relaxed; you may want to make it more strict.)
Finally, add an MX record for the domain. This means that all incoming mail for the domain will go to this mail server.
Now the server is all set up… except that you probably need a user that’ll receive email there.
You may want to choose a different name (if you have a different name).
Let’s see what the mails look like now:
Mail-Tester is a convenient tool to test how it all went.
Perfect!
Even Gmail can’t complain about your mail now.
Well… unless they do. They’ll probably find some other hoops to run through any day now, but for the moment you should be OK. Oh, and if you’ve provisioned a server that happened to get the IP address of a previous notorious spammer, you may find that your mail gets tagged as spam, anyway. In practice, if you use a reputable hosting service, this isn’t a big problem, but it can happen. If that’s the case, try again and get a new IP address.
Anyway, it might be helpful to also show how to connect to the MTA, right? As an example, here’s Evolution:
Basic info.
IMAP on port 993 (with TLS).
Outgoing email on port 465, with TLS and authentication. Done!
The reason I started thinking about writing this script (and blog post) is twofold: I think it’s a shame that we’re devolving from a decentralised infrastructure for email to a centralised one (i.e., Gmail). We can all see where Gmail is heading — towards a total silo, but it hasn’t quite gotten there yet, because they still have to interoperate somewhat with the rest of the world.
The other is that it’s really annoying that (apparently) nobody has done this before. It’s not like any of the things that the script does is difficult: It’s just that if you don’t know what you’re supposed to do, you can spend hours Googling around, and you’ll mostly get outdated information. For instance, if you search for “exim authentication”, you’ll find this official-looking page that gives horrendous tips like “You also need to add the Debian-exim user into the shadow group, so as to give Exim access to /etc/shadow via PAM.”
No! You should absolutely not let the exim process read the /etc/shadow file, because that’s a way to escalate bugs in the exim server.
And so on.
The script is on Microsoft Github, and pull requests are very welcome. I’m sure there’s many things that can be improved.