Just about any and every server needs to be able to send email - whether it's end-user-email, like password recovery services for a website to emails to system administrators reporting on the status of system backups and errors. The problem is that it's non trivial (understatement) to set up a mail server properly.
This howto assumes you have a Linux server (these instructions are for Ubuntu 18.04, although it should work on earlier versions of Ubuntu server and Debian Linux without many changes, and the concepts will be very similar on other Linuxen) with a static IP address, with one or more fully-qualified-domain-names (fdqn) pointing at that address, and you have SSH-based access to it. I've previously provided tips on how to get to this stage.
MailCow for authenticating SMTP
To send email, you need access to a server, somewhere on the Internet, that provides the Simple Mail Transfer Protocol (SMTP) service. It's an open standard, and for most of the history of the Internet, email services have been mostly provided by Free and Open Source Software (FOSS) tools - the first SMTP was called "Sendmail" and it was fully FOSS, and it's still in use today (although it has mostly been superseded by faster, more secure systems, the best of which are also FOSS).
At the OERu, we use the Docker-based installation of the amazing, completely FOSS MailCow project to provide our organisational email services. I might cover that set up in a future howto here, because MailCow makes an otherwise almost intractable problem... much more tractable. Having set up MailCow set up means we can offer "full service" email for any number of domains and users and aliases with all the bells and whistles including incoming and outgoing mail with all the virus scanning (we don't really need it because we use Linux desktops, but for other folks it's useful I guess) and dynamic spam filtering services you'd expect from a much larger operation: Team MailCow have done an amazing job in pulling together a comprehensive set of FOSS applications to provide all the conceivable requirements of a full-fledged, multi-domain email system, including shared calendaring, contacts, and webmail. A great companion to your organisation's MailCow server would be a BitWarden password safe server... just sayin'. With a tiny bit of configuration cleverness, you could even run them both simultaneously on the same server... but that's a story for another day.
So, now, assuming that we have a MailCow server or a functionally equivalent SMTP service available, we have the option of "authenticated SMTP" for outgoing email using credentials we can set up. For example, in MailCow, we can specify a domain we host, like say oeru.org (and for which we've defined an MX record and a few other relevant records as guided by MailCow administrative web interface). On top of that, we can specify a mailbox for a dedicated "send stuff from remote relay hosts" email address using that domain, like firstname.lastname@example.org, with a strong password. With that, we can securely send email using that email address as the username and that password from anywhere we have access to the Internet.
The only tricky part is that we have to ensure that whatever "reply to" email address we specify from our applications, say email@example.com, is using a domain we also host on the same server, and that there's an email alias of that email address defined and set as "allow to send from firstname.lastname@example.org" in the MailCow interface. If we haven't made sure of that, our mail server is likely to reject sending emails with that "mismatching" email address. This is a basic spam deterrence measure, which is for the best, despite sometimes making a email system administrator's life harder.
Once we've got that (and it's easy once you've done it once or twice - I'm mostly writing this down now so I don't have to try to re-remember every time I need to set up a new server - and I hope it helps others, too), we can set up any server we control to send secure (and spam-filter-resilient) email. For what it's worth, too, MailCow uses Postfix as its SMTP server component (there're a bunch of other components, too).
Postfix SMTP with SmartHost
The first thing you need to do to create a postfix smarthost is to install the postfix application on a new server (this assumes you're logged in with a user who has "sudo" - aka admin - permissions):
sudo apt update && sudo apt install postfix bsd-mailx
During the install, you'll be asked to select a bunch of configuration parameters. Select the defaults except:
- Select "Internet Site with Smarthost",
- fill in the domain name for your server,
- the domain name and port (in the form
[smtp server domain]:[port], e.g.
smtp.oeru.org:587) of your "smarthost" who'll be doing the authenticating SMTP for you, and
- the email address to which you want to receive system-related messages.
After that's done, you can proceed.
For the rest of this howto, you'll need to do the following. First, select your text editor. I use vim, but if you're new to the command line, I recommend using nano - it's more straightforward:
EDIT=`which nano` or
sudo $EDIT /etc/aliases
We need to make sure the "root" user points to a real email address. Add a line at the bottom which says (replacing [your email] with your email :) )
root: [your email]
After which you'll need to convert the aliases file into a form that postfix can process, simply by running this:
Then we have to define the authentication credentials required to convince your mail server that you're you!
sudo $EDIT /etc/postfix/relay_password
The resulting file only needs one line with three bits of information:
[smtp server domain] [user name]:[password]
Then save the file and, like the aliases file, run the conversion process (which uses a slightly different mechanism):
sudo postmap /etc/postfix/relay_password
Finally, we'll edit the main configuration file for Postfix to tell it about all this stuff:
sudo $EDIT /etc/postfix/main.cf
If your SMTP server uses port 25 (the default for unencrypted SMTP) you don't have to change anything, although most people nowadays prefer to use StartTLS or otherwise encrypted transport to at least ensure that your SMTP authentication details (at least) are transferred encrypted. That means using port 587 or 465. If you're using either of those ports, find the "relayhost = [your server name]" line... and add your port number after a colon, like this
relayhost = smtp.oeru.org:465
Next, add the following lines at the bottom of the file:
# added to configure accessing the relay host via authenticating SMTP
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/relay_password
smtp_tls_security_level = encrypt
Save the file, and then check that your syntax is correct:
sudo postfix check
If it is (running the command returns no errors, and it might not return anything at all - that's a good thing!), then you can run
sudo postfix reload
to get postfix to reload its configurations and you can test out your new smarthost-configured SMTP server!
If not, the output of the check command will usually give you a helpful insight into what is wrong with your configuration... you'll also find that looking at the mail log is very helpful and offers great insights:
sudo less +G /var/log/mail.log
and if you're not able to fix it based on those, you'll find postfix is widely documented and has rich set of easily discoverable resources out there on the web - a search engine is your best resource!
Testing your outgoing email
By default, a command line application called "mail" is installed as part of the bsd-mailx package we installed alongside postfix. You can use it to send test email from the command line on your host to verify you've got things working correctly! The stuff in <> are the keys to hit at the end of the line...
$ mail email@example.com<ENTER>
Subject: Testing from your.relay.server.domain<ENTER>
Testing postfix remote host<ENTER>
Typing <CTRL-D> (hold down the Control or Ctrl key on your keyboard and press the "d" key) will finish your message, showing you a "CC:" field, in which you can type in other email addresses if you want to test sending to multiple addresses. When you then hit <ENTER>, it will attempt to send this email. It might take a few minutes to work its way through to the receiving email system (having to run the gauntlet of spam and virus filters on the way).
You can also always check the postfix system logs to see what postfix thinks about it using the command above. Hit <SHIFT-F> to have the log update in real time.
Now you've got working outgoing email from your server. That means many higher-level web applications you might install on your infrastructure will work out-of-the-box, because what you've set up, for example, enables the default PHP email service and that used by other stacks.
Sending from Docker Containers
You can configure your server so you can reference it from services you run from Docker containers on your host. You do this by referencing the host, like via an ad hoc SMTP server on your container like msmtp, and you can just reference it as 172.17.0.1, which is the default base IP for Docker hosts from the perspective of Docker containers. You might find it's different on your particular install. In that case, you have to make your Postfix SmartHost accept email for sending from the Docker containers on that server. There're quite a few examples of that among my Docker recipes on the OERu's git repository.