SMTP relay through Fastmail from Postfix on macOS Mojave

When my Mac laptop tries to send me email — the output of a cron job, for example — by default it ends up in a local mailbox file that I never check. I want the mail to get to my regular email account, but I don’t want it to relay that message through whatever random ISP I might be connected to at any given time, or over the open internet. It’ll likely fail, it’s not secure, and there are better ways.

Instead, I relay all outgoing mail sent from macOS through my email provider, Fastmail (affiliate link). This especially makes sense since most of the email from my OS is going straight to my inbox hosted at Fastmail.

The notion of relaying email through a specific provider is built in to the Postfix mail transport agent that comes with macOS, so in theory it’s not a big deal to set up. In reality, I’ve found it to be a somewhat fragile configuration, and rarely does it survive a macOS upgrade or switch to a new computer. So I’ve come to document it pretty heavily for my own reference. I recently went through the process again, so thought I’d write it up here in case it’s helpful to others.

Most of these steps are derived from this nice compilation of steps that applies to macOS Sierra through Mojave.

  1. Edit /etc/postfix/ and add these lines to the end:

	smtp_sasl_auth_enable = yes
	smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
	smtp_sasl_security_options = noanonymous
	smtp_sasl_mechanism_filter = PLAIN, LOGIN
	smtp_use_tls = yes
	smtp_tls_security_level = encrypt
	smtp_tls_mandatory_ciphers = high
	smtp_tls_verify_cert_match = nexthop
	smtp_sasl_tls_security_options = noanonymous
	smtp_tls_CAfile = /etc/postfix/ssl/ca-bundle.crt
	relayhost =
  1. Generate a modern certificate bundle that Postfix can use, using the macOS keychain (share). This step is important because I’ve found that the server certificate Fastmail uses from Digicert is not included in the default SSL cert bundle available to Postfix, and you’ll get errors like “certificate verification failed for” that prevent the mail from being relayed.
$ sudo security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain > /etc/postfix/ssl/ca-bundle.crt

To be safe you might want to put that in a cron job. Or just make it a special New Year’s Eve tradition.

  1. Create a password file for Postfix to use in logging in to your Fastmail account, at /etc/postfix/sasl_passwd. The format is like so:

where is replaced with your Fastmail account username (which might normally look like but uses # istead of @ in this context) and password is an application password that you’ve created just for use in this relaying setup. It only needs SMTP access:

Please do not use your main Fastmail account password. Once the file is populated, run sudo postmap /etc/postfix/sasl_passwd.

  1. Follow the “Autorun postfix on boot and restart postfix” steps in the gist file mentioned above, exactly as listed. Here’s what the plist file looked like when I was done:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "">
<plist version="1.0">

Then, relaunch the Postfix daemon and confirm:

$ sudo launchctl unload /Library/LaunchDaemons/org.postfix.custom.plist
$ sudo launchctl load /Library/LaunchDaemons/org.postfix.custom.plist
$ sudo launchctl list | grep org.postfix
  1. Test:
echo "Test sending email from Postfix" | mail -s "Test Postfix"

You should get an email in your inbox with the message sent from your macOS through Fastmail, with no other intermediate SMTP server hopping. Check the email headers to be sure.

Received: from mac.localdomain ( [])
	by (Postfix) with ESMTPA id XXXXXXXXX
	for <>; Fri, 27 Nov 2020 13:19:16 -0500 (EST)
Received: by mac.localdomain (Postfix, from userid XXX)
	id XXXXXXXXXXXX; Wed, 25 Nov 2020 05:00:08 -0500 (EST)

If it doesn’t work, you might be tempted to go look for a mail log in /var/log…but it doesn’t exist any more in modern versions of macOS. SIGH. I didn’t bother to research the architecture decision here, I just shook my head at it. But you can “tail” the “log file” for mail-related transactions using this special command:

log stream --predicate '(process == "smtpd") || (process == "smtp") || (process == "master")' -info

That’s “all.” I’m sure it will be outdated again soon, but I hope it helps someone else anyway.

Published by

Chris Hardie

I'm a deep generalist, currently focused on software engineering + writing + the open web.

Leave a Reply

Your email address will not be published. Required fields are marked *