In this article we are going to install and configure Postfix to allow our applications to use the PHP mail() function. Tested and working on Ubuntu 20.04, 18.04 & 16.04.

1. Install Postfix

Let’s update the package database first.

sudo apt-get update

Install mailutils, which will automatically install Postfix.

sudo apt install -y mailutils

On the first Postfix configuration screen, select OK by pressing TAB and ENTER

postfix-config1-1024x682

Select Internet Site and press ENTER.

postfix-config2-1-1024x683

System mail name should be your domain name eg. example.com, press ENTER.

postfix-config3-1024x682

Package should now be installed.

2. Configure Postfix

For security reasons, you should instruct Postfix only to process requests to send emails from the server on which it is running.

Edit the Postfix configuration file.

sudo nano /etc/postfix/main.cf

Towards the bottom of the file, find the line inet_interfaces = all. (Press CTRL + W to search) Change it to:

inet_interfaces = loopback-only

Save file and exit. (Press CTRL + X, press Y and then press ENTER)

Lastly, let’s restart Postfix.

sudo systemctl restart postfix

If you intend on sending email to your own domain, Postfix requires some additional configuration. For example, I want my PHP app to send emails to info@devanswers.co. This will fail if you don’t make some additional changes to your main.cf file. 

Can’t send mail to own domain. Postfix: status=bounced (unknown user: “user”)

Having problems sending email to your own domain? You may need to change your postfix configuration.

I was experiencing a problem sending mail to an address at my own domain. I wanted my PHP app to send notification emails to info@devanswers.co but they kept bouncing with “status=bounced (unknown user: “user”)”.

Accessing the log:

sudo tail /var/log/mail.log -n 200

This will return the last 200 lines of the log.

Log output:

May 24 12:28:04 example postfix/pickup[30776]: DC48FC0927: uid=33 from=
May 24 12:28:04 example postfix/cleanup[32746]: DC48FC0927: message-id=<7662c91b0e00d2a3eb28eb1dbee01d98@178.62.26.57>
May 24 12:28:04 example postfix/qmgr[1711]: DC48FC0927: from=<www-data@example.com>, size=9136, nrcpt=1 (queue active)
May 24 12:28:04 example postfix/local[32748]: DC48FC0927: to=<info@example.com>, relay=local, delay=0.06, delays=0.03/0.01/0/0.01, dsn=5.1.1, status=bounced (unknown user: "user")
May 24 12:28:04 example postfix/cleanup[32746]: E7413C0928: message-id=<20170524122804.E7413C0928@example.com>
May 24 12:28:04 example postfix/qmgr[1711]: E7413C0928: from=<>, size=10993, nrcpt=1 (queue active)
May 24 12:28:04 example postfix/bounce[32749]: DC48FC0927: sender non-delivery notification: E7413C0928
May 24 12:28:04 example postfix/qmgr[1711]: DC48FC0927: removed
May 24 12:28:04 example postfix/local[32748]: E7413C0928: to=<www-data@example.com>, relay=local, delay=0.01, delays=0/0/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
May 24 12:28:04 example postfix/qmgr[1711]: E7413C0928: removed
May 24 12:28:04 example postfix/pickup[30776]: EBC48C0927: uid=33 from=
May 24 12:28:04 example postfix/cleanup[32746]: EBC48C0927: message-id=<a12cabb6f7b6df7c5d342985f4eed746@178.62.26.57>
May 24 12:28:04 example postfix/qmgr[1711]: EBC48C0927: from=<www-data@example.com>, size=8898, nrcpt=1 (queue active)

 

I’m not sure if others have experienced this issue, but if your email server is hosted on another domain and you use postfix and SMTP to send local emails from a PHP web form for example, then you need to setup the following in your postfix configuration.

Open your Postfix config file.

sudo nano /etc/postfix/main.cf

Scroll down and look for the entries for myhostname and mydestination. Change them so they look like this.

. . .
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = localhost
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
. . .

 

This forces postfix to always use the external email server, even in a case the email recipient is under your local domain name, like myself@mydomain.com.

Lastly, let’s restart Postfix.

sudo systemctl restart postfix

You can send a test email to see if it works.

echo "Test Email message body" | mail -s "Email test subject" example@example.com

 

3. Test Postfix

We’ll now send a test email message. Make sure to replace test@example.com with your own email address.

echo “Test Email message body” | mail -s “Email test subject” test@example.com

Don’t forget to check your spam folder.

If you still haven’t received any mail after a few minutes, check the mail error log.

sudo tail /var/log/mail.log

If the mail log is empty or doesn’t give enough information, try parsing the syslog. This will return the last 50 entries for postfix.

sudo tail -f -n 50 /var/log/syslog | grep postfix

If the syslog is empty and you still haven’t received any test email, it’s possible that the test email was rejected by the recipient server. You should check to see if anything has bounced back to your mail folder.

sudo less /var/mail/$(whoami)

Press uppercase G to scroll to the bottom of the file and lowercase q to quit. The $(whoami) variable returns the currently logged in user. 

4. Test PHP mail()

If Postfix is working correctly, you should now be able to send mail via PHP mail().

Mail Never Received / Spam Issues

If emails are being rejected by the remote mail provider (such as Gmail), or mail is going straight to your email client’s spam folder, you may need to do some additional configuration on your domain (SPF, DKIM, DMARC records) to get past spam filters.