Monday, January 26, 2015

Setup Postfix with a remote SMTP relay host

Setup Postfix with a remote SMTP relay host


Postfix config
Postfix config
Platforms: 
any Linux distro
What You'll Need:
Postfix 2.2+
cyrus-sasl 2.1.19+
3rd party email account
Sending outgoing email thru a 3rd party SMTP relay service is a quick and easy alternative to setting up a full fledged local email server. Google Apps/Gmail, Yahoo, and many ISPs provide SMTP relaying for free. This guide will cover configuring Postfix on a CentOS server to relay outgoing email to a 3rd party.
Most Linux distros come with Sendmail already installed, and is usually the default mail client used by the running services. However, Postfix beats the crap out of Sendmail and is a complete, seamless replacement. Here's how I got it going on my CentOS box.

Install

Install Postfix and cyrus-sasl with your application manager of choice. If you're compiling from source, be sure to make Postfix with the -DUSE_SASL_AUTH flag for SASL support and -DUSE_TLS for TLS support.
Note: CentOS 6+ now packages cyrus-sasl-plain separately, so if it's not specifically installed, you'll get a "Authentication failed: cannot SASL authenticate to server ...: no mechanism available" error.
$ yum install postfix cyrus-sasl cyrus-sasl-plain
Stop the sendmail service
$ /etc/init.d/sendmail stop
Remove sendmail from the startup runlevels
$ chkconfig --del sendmail


Typical Setup

Edit /etc/postfix/main.cf
# Set this to your server's fully qualified domain name.
# If you don't have a internet domain name,
# use the default or your email addy's domain - it'll keep
# postfix from generating warnings all the time in the logs
mydomain = local.domain
myhostname = host.local.domain
# Set this to your email provider's smtp server.
# A lot of ISP's (ie. Cox) block the default port 25
# for home users to prevent spamming.  So we'll use port 80
relayhost = yourisp.smtp.servername:80
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = smtpd
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_type = cyrus
smtp_sasl_auth_enable = yes
# optional: necessary if email provider uses load balancing and
# forwards emails to another smtp server
# for delivery (ie: smtp.yahoo.com --> smtp.phx.1.yahoo.com)
smtp_cname_overrides_servername = no
# optional: necessary if email provider
# requires passwords sent in clear text
smtp_sasl_security_options = noanonymous
There's roughly a 99.9% chance that your email provider's SMTP server requires authentication. We need to set that up with the username and password given by your email provider.
Add the following line to /etc/postfix/sasl_passwd
yourisp.smtp.servername:80 username:password
The above server hostname and port must exactly match the value for "relayhost" in /etc/postfix/main.cf.
Generate a postfix lookup table from the previous file
$ postmap hash:/etc/postfix/sasl_passwd
Test the lookup table, if all is good then the following will return the specified username:password
$ postmap -q yourisp.smtp.servername:80 /etc/postfix/sasl_passwd
Make sure the sasl_passwd and sasl_passwd.db files are readable/writable only by root
$ chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
Add postfix to be started at boot
$ chkconfig --add postfix
Fire up Postfix
$ /etc/init.d/postfix start
Test it out using sendmail alias from the command prompt
$ $ sendmail -t
To: to.address@example.com
From: from.address@example.com
Subject: Test 123
Postfix is good to go.
.


Gmail Setup

If you're attempting to relay mail using Gmail, then it will be necessary to use TLS with Postfix. You'll have to point Postfix at your server's trusted CA root certificate bundle, but luckily "...client-side certificates are not required when relaying mail to GMail".
First, double-check that Postfix was configured with SSL support (ie. ldd should return at least one line starting with libssl):

$ whereis -b postfix
postfix: /usr/sbin/postfix /etc/postfix /usr/libexec/postfix
$ ldd /usr/sbin/postfix
...
libssl.so.6 => /lib/libssl.so.6 (0x00111000)
...
Now we need to find your server's CA root certificate bundle, which is typically distributed with openssl. The bundle file is used by Postfix to verify Gmail's SSL certificate (signed by Thawte). On my CentOS server, this file was located at /etc/pki/tls/certs/ca-bundle.crt, but may be in a different location on your OS (ie. /etc/ssl/certs).

$ locate ca-bundle.crt
/etc/pki/tls/certs/ca-bundle.crt
Edit /etc/postfix/main.cf with the following values:

relayhost = smtp.gmail.com:587
# your FQDN, or default value below
mydomain = local.domain
# your local machine name, or default value below
myhostname = host.local.domain
myorigin = $myhostname
# SASL
smtpd_sasl_path = smtpd
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_type = cyrus
smtp_sasl_auth_enable = yes
smtp_sasl_security_options = noanonymous
# TLS
smtp_use_tls  = yes
smtp_tls_CAfile = /path/to/your/ca-bundle.crt
smtp_sasl_tls_security_options = noanonymous
If you haven't already, add the following to /etc/postfix/sasl_passwd

smtp.gmail.com:587 username:password
Generate a postfix lookup table from the previous file
$ postmap hash:/etc/postfix/sasl_passwd
Make sure the sasl_passwd and sasl_passwd.db files are readable/writable only by root
$ chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
Restart postfix and send a test email

$ postfix reload
$ sendmail -t
To: to.address@example.com
From: from.address@example.com
Subject: Testing 123
Test relay thru Gmail
.
If this is a new Google email account, make sure to login to the gmail web interface with it first. You'll need to accept the Google TOS before you can send any email thru the account.
Note that Google places daily limits on the amount of emails and recipients.

Sending from multiple email accounts

Postfix 2.3+ can also be setup to authenticate, relay, and send from multiple email accounts (see Configuring Sender-Dependent SASL authentication). Postfix will lookup and relay to the appropriate host based on the sender address specified by the client. This can be configured using a per-sender relayhost file that maps each sender addresses to a relay provider. Clients must specify a sender address when composing an email so that Postfix can lookup the appropriate sender's relay host info.
Let's assume we'll be sending from two email accounts: foo@foo.com (which uses smtp.gmail.com:587) and bar@bar.com (which uses smtp.bar.com:666). We'll first add them to the /etc/postfix/sasl_passwd, along with a default relay host and user (smtp.gmail.com:587/foo@bar.com) which will be used as the sender in case a client omits the sender address or a matching sender address is not found:
foo@foo.com foo@foo.com:password
bar@bar.com bar@bar.com:password
smtp.gmail.com:587 foo@foo.com:password

Generate a postfix lookup table from the previous file
$ postmap hash:/etc/postfix/sasl_passwd
Next, add the senders and their providers to a new /etc/postfix/sender_relay file
foo@foo.com smtp.gmail.com:587
bar@bar.com smtp.bar.com:666

Generate a postfix lookup table from the previous file
$ postmap hash:/etc/postfix/sender_relay

Make sure the all above files are readable/writable only by root
$ chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db /etc/postfix/sender_relay /etc/postfix/sender_relay.db

Next, add the following directives to /etc/postfix/main.cf for multiple relay host support (this assumes you've already added the smtp_sasl_* directives mentioned earlier in this article)

# multiple sender relayhost maps
sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay
smtp_sender_dependent_authentication = yes

Finally, reload Postfix and send some test messages
$ /etc/init.d/postfix reload
$ sendmail -tf "foo@foo.com"
To: to.address@example.com
From: foo@foo.com
Test email should be from foo@foo.com
.
$ sendmail -tf "bar@bar.com"
To: to.address@example.com
From: bar@bar.com
This test email should be from bar@bar.com
.

Note: the sendmail -f argument is required for Postfix to select the appropriate sender and relay host. Also, if the "From:" message header is omitted, Postfix will automatically set the NAME environment variable as the sender's display name (the correct sender relay host is still used). Use the -F argument to set a custom display name, or specify the "From:" message header (though this latter option seems to be buggy and is ignored).

A quick note about sending email from WordPress

At the current version of 3.6.1, WordPress does not set the sender on outgoing emails. So on a server configured to relay thru multiple outgoing email accounts, all outgoing WordPress emails will be sent via the default relay host (specified in /etc/postfix/sasl_passwd).
A quick fix is to set the Sender attribute of WordPress's phpmailer object. This can be done by adding the following code to your theme's functions.php file, which will set the sender as the address specified in theWordPress admin > General Settings > Email Address.
function phpmailer_set_sender_address($phpmailer){
    $phpmailer->Sender = get_option('admin_email');
}
add_action('phpmailer_init''phpmailer_set_sender_address', 10, 1);
Alternatively, the sender address could be hardcoded above instead of using the WordPress admin email.

Other notes

Anytime you change the /etc/postfix/sasl_passwd or /etc/postfix/sender_relay files, remember to rehash them and reload Postfix
$ postmap hash:/etc/postfix/sasl_passwd
$ postmap hash:/etc/postfix/sender_relay
$ /etc/init.d/postfix reload


Troubleshooting

Monitor postfix mail log in a separate session with the following command
$ tail -f /var/log/maillog
If the log is displaying the following error
(Authentication failed: cannot SASL authenticate to server ...: no mechanism available)
then set this variable in /etc/postfix/main.cf
smtp_sasl_security_options = noanonymous
If the log is displaying this error
553 Sorry, that domain isn't in my list of allowed rcpthosts. (in reply to RCPT TO command)
check your username and password in /etc/postfix/sasl_passwd. Your user name is usually your full email address. If you have to fix it, don't forget to use postmap to generate a new lookup table.