Relay mail with Office 365 and Postfix

Email notifications from your server are not very useful if you need to log into the box to check them. I've set up Postfix to work with Gmail and Mailgun in the past, but this was my first run in with Office 365. The setup works out to be relatively the same, but there are a few extra steps required for Office 365 to work correctly.

Keep in mind I'm running on an Ubuntu 16.04 LTS box, so if you're on something else there might be some slight deviations from the following.

Install Posfix and dependencies

Let's get started by installing Postfix and necessary dependencies. If it's been a while since you've used apt don't forget to run apt-get update.

sudo apt-get update  
sudo apt-get install postfix sasl2-bin mailutils  
Postfix Install Time Configuation

During the Postfix configuation select Internet Site for the General type of mail configuation.
Postfix configuation: Internet Site

Set your System mail name, use your FQDN (Fully Qualified Domain Name) here.
Postfix configuration: System Mail Name

Credentials

Before any mail can be sent through our relay host, Office 365 in this case, we need to define the credentials that will be used to establish the connection. Create a file called sasl_passwd in /etc/postfix.

sudo nano /etc/postfix/sasl_passwd  

In our credentials file we'll define the SMTP server, the username, and the password. Replace user@domain.tld and password with the appropriate credentials.

[smtp.office365.com]:587 user@domain.tld:password

Keep in mind when using Office 365 the user you connect with can only send mail as itself or as a user it has Send As permissions for.

We've got our credentials saved, but we need to do some work for Postfix to be able to use them.

sudo postmap hash:/etc/postfix/sasl_passwd  

We can see that it worked if we run a quick ls /etc/postfix. You should see sasl_passwd and sasl_passwd.db in the list.

For good measure let's also make sure the owner of the files is the root user and the permissions are 644.

sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db  
sudo chmod 644 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db  

Sender

Remember how in Office 365 we can only send as the user we are connecting with or an account that user has Send As permission on? Senders are kind of a free for all depending on what is sending the mail. Cron might be root@myserver while an application might be someapp@myserver.

To fix this problem we need to map our senders to the user we are connecting to Office 365 with. Craete a file called sender_canonical in /etc/postfix.

sudo nano /etc/postfix/sender_canonical  

In this file we'll use a regular expression to map any sender to our Office 365 user.

/.+/ user@domain.tld

Note the use of a + rather than a *. Using the * wildcard could lead you to a mail loop if a message is undeliverable.

Like before we need to make this file useable for Postfix and we'll set the owner and permissions.

sudo postmap hash:/etc/postfix/sender_canonical  
sudo chown root:root /etc/postfix/sender_canonical /etc/postfix/sender_canonical.db  
sudo chmod 644 /etc/postfix/sender_canonical /etc/postfix/sender_canonical.db  

Postfix Config

Finally, let's bring everything together in the Postfix config. We'll need to modify main.cf in /etc/postfix.

sudo nano /etc/postfix/main.cf  

We'll change the folloing line of our main.cf

relayhost =  

to

relayhost = [smtp.office365.com]:587  

Then we'll add the following lines to our main.cf

smtp_sasl_auth_enable = yes  
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd  
smtp_sasl_security_options = noanonymous

smtp_tls_security_level = may

sender_canonical_maps = regexp:/etc/postfix/sender_canonical  

Save main.cf and restart Posfix.

sudo service postfix restart  

Testing

Send a test message to see if everything worked. Replace you@somehost.tld with the address you want to send your test to.

echo "Test Message" | mail -s "Test Subject" you@somehost.tld  

Troubleshooting

If your test fails you can check the mail.log file to try and determine why.

cat /var/log/mail.log | less  

After making changes be sure to restart Postfix before testing.

sudo service postfix restart  
Network is unreachable

If you see a message like:

connect to smtp.office365.com[some ipv6 address]:587: Network is unreachable  

Try changing the inet_protocols line in /etc/postfix/main.cf from all to ipv4.

inet_protocols = ipv4  
Looping or unknown user

If you are sending to a user that is part of the same domain as the server and your log seems to show Postfix is stuck in a mail loop or if you see a message like:

to=<user@domain.tld>, relay=local, ..... staus=bounced (unknown user: "user")  

Try removing domain.tld from the mydestination setting in /etc/postfix/main.cf. In this case server_hostname will be you server's hostname.

mydestination = $myhostname, server_hostname, localhost.localdomain, localhost