Fixing Postfix: Make mail exit your Linux-box
Monday, April 7. 2014
Us server guys are becoming a rare breed. Any server-related tasks can be outsourced to any free-of-charge cloud service provider. One very good example of that is e-mail, nobody runs their own mail server nowadays. Companies are using external services and any regular Joe and Jane have gone for Gmail years ago. However, once in a while something funny happens and people want a NSA-free e-mail account.
The fact is that every Linux-installation has a mail server installed and running in it. The purpose for the mail server is to deliver local in-server mail to user(s), also depending on your Internet-connection it may be possible to send outgoing mail to the wild wild Net. Most ISPs block this due to excessive spamming from consumer's computers.
Setting up a receiving Postfix MTA is outside of this blog post, but my idea is to present you configuration help to:
- Configure Postfix to tunnel outgoing e-mail via you ISP's SMTP
- (optional) Redirect root's e-mail to an external mailbox
- (optional) Increase mail transport security by using TLS encryption for e-mail
So ... here goes.
Configure Postfix to tunnel outgoing e-mail via you ISP's SMTP
To fight spam most (all reasonable) ISPs have blocked outgoing TCP/25 traffic. This very effectively makes your computer not being able to inject new e-mails into receiving servers. Because of this, for example Google instructs users to use TCP-ports 465 or 587 instead, see their setup instructions.
For a mail server (like your Postfix), that is not a solution. Your box must be able to deliver e-mail to any server's TCP/25. All ISPs I've ever seen share a SMTP-server for their customers. The idea is to route all your external e-mail to that server, it will relay the e-mail to the final destination. Remember, that as a spam prevention measure, the amount of mail you can send via ISP's SMTP is limited. For example my ISP has a 50 e-mails per hour policy. It simply refuses to serve any excess requests based on IP-address of the sender.
The subject of routing outgoing e-mail is covered (among many others) in this article with title Configuring postfix to forward all email to a smtp gateway. All you have to do is add:
transport_maps = hash:/etc/postfix/transport
into your Postfix's main.cf. Typically there is a transport-file, but it does not contain your ISP's configuration in it.
Example:
My ISP TeliaSonera Finland has a SMTP running @ mail.inet.fi. Initially I had following line in my transport-file:
* smtp:mail.inet.fi
But it didn't work! Looking into source code src/trivial-rewrite/resolve.c reveals that Postfix keeps resolving the address via MX-record. The correct one will be:
* smtp:195.156.147.15
This setting will skip any resolving of the given address and use the given IP-address as-is.
Test the setup by sending e-mail to one of your own external addresses. It can be achieved by running something like this:
date | mail -s "Testing outgoing mail" test@user.at.somewhere
Confirm the functionality from Postfix's log, it should read something like this:
postfix/pickup[12869]: D13F8209AF: uid=0 from=<user>
postfix/cleanup[13427]: D13F8209AF: message-id=<20140407161546.D13F8209AF@my.linux.box>
postfix/qmgr[2185]: D13F8209AF: from=<user@my.linux.box>, size=482, nrcpt=1 (queue active)
postfix/smtp[13429]: D13F8209AF: to=<test@user.at.somewhere>, relay=195.156.147.15[195.156.147.15]:25, delay=0.35, delays=0.06/0.01/0.04/0.24, dsn=2.0.0, status=sent (250 <529734CF0ADA3B46> Mail accepted)
postfix/qmgr[2185]: D13F8209AF: removed
It clearly says "Mail accepted" and Postfix's queue manager eventually removes the outgoing mail from outgoing queue. Remember to confirm, that the mail landed to the external mailbox.
Redirect root's e-mail to an external mailbox
A good starting point is to look at /etc/aliases. For example OpenSuse has this in it:
# It is probably best to not work as user root and redirect all
# email to "root" to the address of a HUMAN who deals with this
# system's problems. Then you don't have to check for important
# email too often on the root account.
So, I put this into my aliases:
root: test@user.at.somewhere
There is a catch ... Having that in /etc/aliases won't work for your system's internal e-mails. Now that your box is not a receiving mail server, all of you mail is internal. You can confirm the non-functionality by:
date | mail -s "Testing outgoing root mail" root
Your maillog will read something like in the previous example. Mail will be routed to your ISP's SMTP, but the problem is, that the e-mail address is wrong. It will read root@your.server.name, your ISP does not have a clue what to do with such a mail, and it will bounce back. Now that your server cannot receive mail, the bounce will be dropped and is lost.
There is a fix for that. The two articles of Rewriting to address on postfix local aliases and Postfix masquerading or changing outgoing SMTP email or mail address will contain clues how to do it. I added following line into my main.cf:
smtp_generic_maps = hash:/etc/postfix/generic
The /etc/postfix/generic will read:
root@your.server.name test@user.at.somewhere
Postmap the transport-file, reload the postfix-service and test again. Now Postfix will re-write the outgoing e-mail properly as planned. The re-write can not be confirmed from the maillog, it will display the original root@your.server.name in there. However, on the receiving end the e-mail address will be correct.
Increase mail transport security by using TLS encryption for e-mail
The last item on my checklist is to start encrypting the mail. Note that this is pointless if your ISP does not support encryption. If it does and your Postfix is not configured to use encryption, you will get a lot of "warning: no entropy for TLS key generation: disabling TLS support" in your maillog.
As a prerequisite, you will need a SSL-certificate. Any certificate will do, even a crappy self-signed one. I'd never recommend using self-signed certificates, but if you're lazy and don't want to get a free one from the net, go for the path of least resistance. This is what I have in main.cf:
# SSL/TLS
# SMTP (sending)
smtp_tls_security_level = may
smtp_tls_key_file = /etc/ssl/private/the.certificate.key
smtp_tls_cert_file = /etc/ssl/certs/the.certificate.cer
smtp_tls_CApath = /etc/ssl/certs
To confirm that TLS is being used will look like this on received e-mails headers:
Received: from mail.inet.fi ([2001:15d8:172::]) by
mx.google.com with ESMTPS id 1si12730620lam.174.2014.04.07.09.57.37 for
<test@user.at.somewhere> (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256
bits=128/128); Mon, 07 Apr 2014 09:57:37 -0700 (PDT)
Received: from your.server.name ([172.16.141.138])
(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256
bits)) (No client certificate requested) by mail.inet.fi (Postfix) with
ESMTPS id E75004355F for <test@user.at.somewhere>; Mon, 7 Apr 2014 19:57:35
+0300 (EEST)
Notice how both servers specify the TLS cipher used. In this case Google's server uses only 128-bit encryption.
Note:
You don't need to enable tlsmgr in master.cf for any this to work. I've seen incorrect instructions about that. To repeat: For sending TLS-encrypted e-mail having tlsmgr is not necessary.