Setting up Postfix with external SMTP
Having trouble getting mail to send with Postfix? Learn how to configure Postfix with an external SMTP server.
Getting a new server up and running isn't quite complete until you can send mail for purposes of monitoring. I recently setup a new server this week and configured unattended upgrades but I wanted a way to be notified in case of errors or in the event I needed to login to manually perform an action (reboot after a kernel upgrade, for example). I have used Postfix in the past but always ran into issues getting it to actually work.
First, we need to make sure we have Postfix installed on our server:
$ sudo apt install postfix
sudo dnf install postfix
sudo pacman -S postfix
During the process, it's going to ask you a series of questions. Since we are setting this up to be used with an external SMTP server we will select "Internet Site":
![Postfix Install - Step 1](/img/posts/2022/01/21/postfix-step1.jpg "Select "Internet Only"")
On the next screen, it's going to ask you for your "System mail name". This is the domain used in the email address(es) you'll be using. In my case, that's
You can verify Postfix is installed and running:
$ sudo systemctl status postfix ● postfix.service - Postfix Mail Transport Agent Loaded: loaded (/lib/systemd/system/postfix.service; enabled; vendor preset: enabled) Active: active (exited) since Fri 2022-01-21 15:44:57 UTC; 1h 35min ago Process: 51586 ExecReload=/bin/true (code=exited, status=0/SUCCESS) Main PID: 4378 (code=exited, status=0/SUCCESS)
Here we can see Postfix is running and is also set to start on boot because it shows
enabled. If for some reason it shows
disabled instead, you can make it start on boot by enabling it:
$ sudo systemctl enable postfix
After the installation completes, we now need to configure Postfix. First, let's start by creating the
sasl_passwd file which will contain our credentials for our SMTP server.
$ sudo vim /etc/postfix/sasl_passwd
Inside this file, we'll include three pieces of information:
SMTP server address
You'll want to check with your mail provider to determine what your username is. For some hosts, this username is just the email address itself. If you're using some kind of two-factor authentication, you may need to create an app password to be able to login.
I use Namecheap as my mail host so that's what I'll be using in the following examples. If you use Namecheap, your username will be the full email address of the user you created when setting up the mailbox:
mail.privateemail.com [email protected]:password
Next, we need to set the permissions on this file so that no one else can read it:
$ sudo chmod 600 /etc/postfix/sasl_passwd
For those who don't know,
chmod 600allows "read/write" (6) access to owner and no privileges to group (0) and other (0).
Now, we create a hashed database of this file which Postfix will use. The resulting file will be the same filename with an added .db extension.
$ sudo postmap /etc/postfix/sasl_passwd $ ls -l /etc/postfix/sasl* -rw------- 1 root root 69 Jan 21 16:12 /etc/postfix/sasl_passwd -rw------- 1 root root 12288 Jan 21 16:12 /etc/postfix/sasl_passwd.db
Now, let's open the main Postfix configuration file:
$ sudo vim /etc/postfix/main.cf
In this file, we need to change a few existing options. First, let's set
myhostname to the domain in our email:
myhostname = gradiian.io
Next, we need to remove our domain from the
mydestination list if it's there otherwise mail will be sent locally on the server rather than through our SMTP server:
mydestination = localhost.localdomain, localhost
Lastly, we need to specify our
relayhost which is going to be set to our SMTP server and port:
relayhost = mail.privateemail.com:587
At the bottom of main.cf we will add the following options to properly authenticate with our SMTP server:
smtp_sasl_auth_enable = yes smtp_sasl_security_options = noanonymous smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_use_tls = yes smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
Save and close the file. We'll now reload Postfix and try and send an email:
$ sudo systemctl reload postfix
Let's make sure
$ which mail $
If you don't see the path to mail returned on the next line, you don't have mail installed. You can get this by installing the
$ sudo apt install mailutils
Let's try that again:
$ which mail /usr/bin/mail
Pro Tip: I found it much easier to troubleshoot my Postfix configuration by tailing the mail log in a separate window so I could watch the output of the logs for errors in real time:
$ sudo tail -f /var/log/mail.log
To send a test email, we can use the previoulsy installed
[email protected] in the example below with the email address you wish to send the test email to:
$ echo "This is a test message" | mail -s "My clever subject" [email protected]
Let's check our mail log to see if that message was sent. If you aren't using
tail to watch the output of the log, you can open it in a text editor and check the lines nearest the bottom:
$ vim /var/log/mail.log
Jan 21 16:49:09 localhost postfix/smtp: A0A04429E1: to=[email protected], relay=mail.privateemail.com[220.127.116.11]:587, delay=1.3, delays=0.04/0.01/0.87/0.4, dsn=4.1.8, status=deferred (host mail.privateemail.com[18.104.22.168] said: 450 4.1.8 [email protected]: Sender address rejected: Domain not found (in reply to RCPT TO command))
Notice the last bit: said: 450 4.1.8 [email protected]: Sender address rejected: Domain not found. The server rejected our email because the sender address of [email protected] is invalid. We need to specify a From address that matches an existing email address on our mail host.
Rather than specifying a From address each time we want to send mail, we'll use Postfix's generic maps to rewrite our local address to our actual address.
$ sudo vim /etc/postfix/generic
Inside this file we'll not only map our current user but also for root which will allow mail from the system. Replace 'localhost' in this example with the value you set in
[email protected] [email protected] [email protected] [email protected]
Now, when Postfix gets mail to send, it will map [email protected] to [email protected]. We need to generate a hash of this file as well:
$ sudo postmap /etc/postfix/generic
...and then we'll add it to the bottom of the Postfix configuration, /etc/postfix/main.cf:
smtp_generic_maps = hash:/etc/postfix/generic
Save and close the file and then reload Postfix:
$ sudo systemctl reload postfix
Now, go ahead and send an email again using the same command we used earlier. This time, the email should go through which you can verify in mail.log:
Jan 21 17:16:56 localhost postfix/qmgr: DAC79429E3: from=<[email protected]>, size=349, nrcpt=1 (queue active) Jan 21 17:16:57 localhost postfix/smtp: DAC79429E3: to=<[email protected]>, relay=mail.privateemail.com[22.214.171.124]:587, delay=392, delays=391/0.02/0.87/0.21, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 2961C18000A2) Jan 21 17:16:57 localhost postfix/qmgr: DAC79429E3: removed
status=sent on the second line as well as
250 2.0.0 OK which is a reply back from the SMTP server letting us know that it has successfully sent our mail.
Update (July 6, 2022) - I was setting up a new server with a new email host and ran across an issue while trying to get email sending:
warning: SASL authentication failure: No worthy mechs found SASL authentication failed; cannot authenticate to server ... : no mechanism available
You may need to install the package
libsasl2-modules and reload postfix using
systemctl reload postfix to be able to authenticate.