Local postfix as relay to Amazon SES
root
Introduction
Alright, this is a quick guide for the impatient but otherwise experienced linux admin/hacker/hobbyist. Some past postfix experiences might be advantageous for general understanding and troubleshoooting.
Why would I want a local postfix and relay to another smtp anyway? Simple: When my application code needs to send an e-mail, there is an SMTP server ready to accept the e-mail from me. It will then take care of everything else like re-delivery, dealing with being grey-listed and many other things. Also, if connectivity to the SES SMTP happens to be interrupted it’s no big deal because here too, the local postfix will handle re-sending for me. Nice, huh?
The documentation for setting up postfix as an SMTP relay to Amazon SES is correct but seems incomplete and I had to hunt a few bits of extra information so below is my complete config that I use on my EC2 instances and my development notebook.
Configuration (EC2)
So let’s make this quick, here are the configs:
main.cf
This is just condensed and stripped to the bare minimum. We only acceppt connections from the localhost, this ensures we don’t relay e-mail from any party.
##
## default config (condensed, no coments)
##
queue\_directory = /var/spool/postfix
command\_directory = /usr/sbin
daemon\_directory = /usr/libexec/postfix
mail\_owner = postfix
inet\_interfaces = localhost
mydestination = $myhostname, localhost.$mydomain, localhost
unknown\_local\_recipient\_reject\_code = 550
alias\_maps = hash:/etc/aliases
alias\_database = hash:/etc/aliases
debug\_peer\_level = 2
sendmail\_path = /usr/sbin/sendmail.postfix
newaliases\_path = /usr/bin/newaliases.postfix
mailq\_path = /usr/bin/mailq.postfix
setgid\_group = postdrop
html\_directory = no
manpage\_directory = /usr/share/man
sample\_directory = /usr/share/doc/postfix-2.3.3/samples
readme\_directory = /usr/share/doc/postfix-2.3.3/README\_FILES
##
## some extras
##
inet\_interfaces = loopback-only
masquerade\_domains = $mydomain
##
## use amazon ses via smtp with starttls
##
relayhost = email-smtp.us-east-1.amazonaws.com:25
smtp\_sasl\_auth\_enable = yes
smtp\_sasl\_security\_options = noanonymous
smtp\_sasl\_tls\_security\_options = noanonymous
smtp\_sasl\_password\_maps = hash:/etc/postfix/sasl\_passwd
smtp\_use\_tls = yes
smtp\_tls\_security\_level = encrypt
smtp\_tls\_note\_starttls\_offer = yes
smtp\_tls\_CAfile = /etc/ssl/certs/ca-bundle.crt
master.cf
The only change to the default config is to comment out the fallback line just below smtp and the rest of the master.cf is unchanged
smtp unix - - n - - smtp -v
# When relaying mail as backup MX, disable fallback\_relay to avoid MX loops
relay unix - - n - - smtp
# -o fallback\_relay=
# -o smtp\_helo\_timeout=5 -o smtp\_connect\_timeout=5
Configuration (Development)
When applying the configuration to my development machine I’ve had to copy the ca-bundle.crt file. So for my development machine the last line of the main.cf file looks like this:
smtp\_tls\_CAfile = /etc/ssl/certs/amazon-aws-ca-bundle.crt
Also, the path daemon_directory is different on my notebook. You can figure out the correct path by checking where your package manager installs all the postfix binaries, that’s your daemon_directory. (or just look at the distro’s config before overwriting it)
daemon\_directory = /usr/lib/postfix
And that’s all that’s different between my EC2 and development hosts.
Amazon SES Credentials
Amazon requires sending systems to authenticate against their SMTP, so you need to first create an SES user and password in the AWS SES Console. Those will be generated by Amazon for you and you have 1 (one) opportunity to see/download those credentials. Put them in the file /etc/postfix/sasl_passwd as you can see here:
email-smtp.us-east-1.amazonaws.com:25 <user>:<password>
ses-smtp-prod-335357831.us-east-1.elb.amazonaws.com:25 <user>:<password>
Then run “postmap hash:/etc/postfix/sasl_passwd” and remove the file.
Verify your sender address
Amazon SES only allows you to send from a verified address. So head on over to the AWS Console and add a sender address, wait for the E-Mail and verify the sender address.
Note: If you’re in sandbox mode, the recipient must also be a verified address, otherwise SES will bounce the e-mail!! For test/dev this is usually good enough, if you need to be able to send e-mails anywhere then it’s time to request production access in the AWS Console.
Sending some test e-mails
This was my biggest pitfall when setting SES up. Sendmail must be invoked in a special way so it behaves nicely and the mail will actually be sent. The first line is the shell command, and the rest is typed into the console.
root@remote:/tmp$ sendmail -t -f verifiedsender@example.com
To: recipient@example.com
Subject: Testing postfix relay via Amazon SES
Hey there, this is a test E-Mail!!
.
Note the line with a single dot and nothing else on it. This tells sendmail the body of the e-mail has ended and the e-mail will be sent.
And that’s it already. If you know what you’re doing it’ll take you 10mins tops to set this up and get it running. If you’re doing it for the first time like I did it’s more like 2-3hrs with troubleshooting. Anyway, I hope this will save some folks some time so they can concentrate on more important matters!
Troubleshooting
If you want some debugging Information from postfix, you can append “-v” on the smtp line in the master.cf and restart postfix. The postfix log is /var/log/maillog on most systems. You need to read the log carefully but it’ll tell you everything you need to find most if not all problems.
- Amazon Web Services
- Ssl
- Saslauth
- Iam
- Postfix
- Sasl
- Ses
- Simple Email Service
- Relay
- Ec2
- Sendmail
- Linux
- Amazon
- Shell