Update to my last post about email setup…
As a remote worker, I travel frequently, and often work away from my home office. My workhorse computer is my laptop, which has most of my important data. Unfortunately, I’m not always near a working open wifi, and that happens frequently in my hometown, which is not a super-wired community.
I do a lot of work via email — in fact, much of my job revolves around email, so I frequently need access to the email stored on the IMAP mail servers I use. I have a Gmail (Google Mail) account, and an account on the corporate email servers as well.
To make sure this mail is available when I don’t have a network connection, I use the offlineimap utility, which synchronizes the email stored on the servers periodically with the email stored on my laptop. This means that I have over 3 GB of email on my laptop, but hey, storage is cheap. It also means that when I read email with Mutt — an extremely functional and flexible text-mode email reader — I’m reading it off my hard disk, which is several orders of magnitude faster than reading over a network. Access to messages and sorting is practically instantaneous, as I’ve mentioned before.
The missing piece of the puzzle, though, is sending email. In the past, I’ve had Mutt set up to send through to the proper SMTP servers for each account. This isn’t hard, since Mutt lets you add hooks as you access an account, a folder, or even compose or reply to email on a per-message basis. But the problem is that network access is always slow, and the user interface blocks for many seconds while the email is sent — and I don’t really want to wait, I want to move on with my life and let the computer deal with that stuff, the way it’s supposed to.
There’s also another problem I need to solve — I want my email sending to also work when I’m on a plane. I don’t mean that I expect that email to actually go anywhere, but I want it to look that way to me and my Mutt reader. I don’t want to worry about whether I’m online or offline, I just want to write my email, and feel confident it will be sent when I’m next online.
Enter Postfix — the secure and highly configurable sendmail alternative, originally written by the inestimable Wietse Venema (of tcp_wrappers and other fame). By configuring a local Postfix mail server to handle the actual transfer of email, when I send email, Mutt pops right back instantaneously so I can continue doing my work. And if I’m not online, Postfix will hold that email and try again later when the network is up. And of course, I need this to work for multiple email accounts I use.
Once I started puttering around with Postfix’s many configuration options, I started to understand enough to be dangerous. I looked at the Postfix documentation online, and also a couple of HOWTOs to see how various subsystems work. Here’s how I did it:
- Install Postfix, using PackageKit:
pkcon install postfix
- Set the system to use Postfix as the new MTA:
su -c 'alternatives --config mta'
- Configure Postfix with the following options in /etc/postfix/main.cf:
smtp_sender_dependent_authentication = yes sender_dependent_relayhost_maps = hash:/etc/postfix/sender_relay smtp_sasl_auth_enable = yes smtp_sasl_security_options = noanonymous smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_tls_policy_maps = hash:/etc/postfix/tls_policy smtp_use_tls = yes smtp_tls_note_starttls_offer = yes smtp_tls_CApath = /etc/pki/tls/certs
This did take a little trial and error, I confess, but the results are clear. This set of options allows Postfix to relay email based on the sender address, based on a map file I’ll show you below; enables SASL authentication for Postfix as an SMTP client, using TLS based on a policy map; and allows it to check certificates for validity using the certificates already installed on the system as part of the ca-certificates package.
- Make a new file /etc/postfix/sender_relay, with the following contents, making changes as needed to reflect your Gmail and corporate account:
# per-sender provider; see also /etc/postfix/sasl_passwd firstname.lastname@example.org [smtp.gmail.com]:587 email@example.com [127.0.0.1]:25025
Note that my corporate email is being tunneled through SSH via a local forward, so my email server actually attaches to port 25025 on the localhost address to send email. If your corporate email server is available on the internet, you would probably just use [mail.corp.example], and make sure to include the appropriate TLS stuff later where needed.
- Make a new file /etc/postfix/sasl_passwd, which will contain the authentication information for each of your accounts:
Add a line for each email address that needs to do SMTP authentication. (Update: Thanks, Bo, for the fix to this file.)
- Make a new file /etc/postfix/tls_policy, which will include information on the way in which each account requires Postfix to use SMTP authentication as a client to the appropriate relay host:
GMail requires the use of TLS, so the encrypt rule here ensures that Postfix will do TLS-based authentication when it connects.
- Rebuild all of the affected map files:
cd /etc/postfix postmap sender_relay postmap sasl_passwd postmap tls_policy
Now Postfix is configured. At this point, I needed to reconfigure Mutt, to remove all the smtp_url options I was setting before. By default, Mutt simply uses the system’s locally-installed sendmail to send email; and the Postfix package provides an equivalent sendmail.postfix binary, which the alternatives command above sets up with an appropriate link, so everything on the system continues running like a top without any further problems. Now Mutt will simply call sendmail blindly, and Postfix will handle all that mail as configured above.
Then I just had to turn off the running Sendmail process, and start up Postfix instead:
- Turn off Sendmail:
service sendmail stop
- Start up Postfix:
service postfix start
- UPDATE: You’ll also probably want to have Postfix start by default at boot time:
chkconfig postfix on
Then I sent a couple of messages to make sure everything was working properly, using tail -f /var/log/maillog to watch the results. Now, to get really cool, I decided to add a hook for NetworkManager to take care of reconfiguring Postfix on the fly to automatically defer SMTP activity when offline, and to turn off that deferment and flush the waiting queue when returning online. I simply installed a script into /etc/NetworkManager/dispatcher.d that looks like this:
#!/bin/sh if [ "$2" == "down" ]; then ( /usr/sbin/postconf -e 'defer_transports = smtp' \ && /sbin/service postfix reload ) || : elif [ "$2" == "up" ]; then ( /usr/sbin/postconf -e 'defer_transports =' \ && /sbin/service postfix reload \ && /sbin/service postfix flush ) || : fi
UPDATE (2011-03-15): In step 5 of configuring Postfix, I had left out the port number. The entry in the sasl_passwd file needs to match the one in sender_relay exactly.
Thanks for this follow up post. This looks like a good how to for people to set up and configure postfix for their personal machines.
I hope you didn’t spend too much time on my msmtp recommendation. I missed the fact that you were looking for a way to deal with sending mail offline. For the situation that I was thinking of for myself msmtp is a simple way to hand off mail and is easy to integrate for other apps on the system that pass off mail in addition to mutt. Those systems are, however, online constantly so its easy to use msmtp in that situation.
Just a quick ‘hmm’ question…why don’t you have a cellular data USB adapter or a tether-able phone or similar? I find mine pretty invaluable, it was a big pain not to have access to it while I was in the UK this month…
Great write up. I am doing the same thing and it works great. One typo, though: you use ‘sasl_passwd’ in the postfix main.cf file contents in step 3, but in steps 5 and 7 you spell it ‘sasl_password’.
@Chess — thanks, fixed that. Also, there’s an update to this story here, where I improved the NetworkManager dispatcher script a bit.
Pingback: The Grand Fallacy » They love a good bandwagon.
I had some issues with the sasl_passwd file above. The format you showed was:
But it should be:
which worked for me. Thanks for a great article.
Bo, you’re right — I’ve corrected the article above.