Postfix Relay to SMTP2GO on NixOS
I am in the process of setting up a new NAS/Homeserver. But I nerd sniped myself by wanting to use NixOS on it. So things are going slow. But here's a thing I learned today…
The goal is to set up a Postfix mail server that will allow me to send mails from the machine itself (through bin/sendmail and localhost:25) as well as from other machines in my network and on Docker. There won't be many mails but when there are, they might be important. So mails should be sent through some relay that is well managed and I don't have to admin myself.
I have a real domain name that I am using to address internal services. I simply have DNS names pointing 192.168.1.* addresses. The public domain allows me to get certificates from LetsEncrypt via ACME DNS-01 – but that's another story.
So the idea here is to have an external mail server that is the permitted sender for that domain and a local relay server that simply relays all mail through that external mail server.
smtp2go
The external service I picked is smtp2go. Their free tier should be good enough for my needs.
Setup on their side was simple. Here's the basic steps:
Create an account at smtp2go.com.
Follow the steps to create a verified sender domain under Sender → Verified Senders. Simply create the three CNAME entries in your DNS config.
I changed the hostname for the return path from the suggested random string to “mail”. I think it's a bit nicer in the mail headers later.
Once the CNAMES are set up and verified, you need an SMTP user. Set one up under Sending → SMTP Users.
The username has to be unique among all smtp2go customers, so I used my fully qualified host name nas.example.com
. Be sure to make note of the password.
That's all that is needed on the smtp2go side. They automatically take care of DKIM, SPF and DMARC.
Nix Setup
There are a few things to set up in the configuration.nix
file.
First of all we need to define the service:
- /etc/nixos/configuration.nix
services.postfix = { enable = true; relayHost = "mail.smtp2go.com"; relayPort = 587; hostname = "mail.example.com"; domain = "example.com"; origin = "example.com"; extraConfig = '' smtp_sasl_auth_enable = yes smtp_sasl_password_maps = texthash:/etc/nixos/secrets/postfix-sasl_passwd local_header_rewrite_clients = static:all append_dot_mydomain = yes ''; networks = [ "192.168.1.0/24" "172.17. 0.0/16" ]; };
The first few lines should be pretty self-explanatory. They simply configure the relay via smtp2go and tell postfix to use my domain.
The extra config enables the authentication at the external mail host (more on that in a second) and it ensures that mails that don't have a proper sender address will have my domain added.
Finally the networks that may use this postfix as relay are added.
Now for authentication we need that postfix-sasl_passwd
file.
It contains a single line:
- /etc/nixos/secrets/postfix-sasl_passwd
[mail.smtp2go.com]:587 nas.example.com:mypassword
It tells postfix which username (nas.example.com) and which password (the one created earlier) to use when talking to smtp2go.
This config would be enough if you only want to access the postfix from the local machine. If you want to relay mail from your local network, you also need to open the firewall.
networking.firewall.allowedTCPPorts = [ 25 ];
After a nixos-rebuild switch
your postfix relay should be working.
Testing
To test, install the mailutils
package on your nix system (or start a shell with nix-shell -p mailutils
) then send a mail to the outside world:
echo "hello world" | mail -s hello example@gmail.com
For testing via the network swaks is the best solution. On my Arch laptop:
yay -S swaks swaks --to example@gmail.com --server 192.168.1.33
The ususal systemd tools for inspecting logs as well as the Reports → Activity page in smtp2go are helpful for debugging when something goes wrong.
Secrets Management? TBD.
For now I put the plain text password into secrets/postfix-sasl_passwd. Ideally I would use some kind of secrets management instead.
agenix seems to be the tool of choice here.
However piecing together the above config already took me the better half of the day, so that has to wait. As intriguing and cool the declarative configuration of Nix is, it does make things harder to set up than just editing a bunch of config files. Or to quote "sorbits" on Hackernews:
The problem I see with NixOS on a typical personal server is that you have to setup all these things using nix expressions, from which the actual configuration files are generated.
That means if you e.g. want to install postfix, instead of learning about main.cf you have to learn the syntax of the nix configuration wrapper for postfix, and postfix having hundreds if not thousands of options, many referring to external files/databases, you have to hope that whoever did this configuration wrapper, supported all the features of postfix that you want to use.