Linux, musical road-dogging, and daily life by Paul W. Frields
 
Best in show.

Best in show.

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:

  1. Install Postfix, using PackageKit:
    pkcon install postfix
  2. Set the system to use Postfix as the new MTA:
    su -c 'alternatives --config mta'
  3. 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.

  4. 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
    your_gmail_address@gmail.com  [smtp.gmail.com]:587
    my_corp_address@corp.example  [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.

  5. Make a new file /etc/postfix/sasl_passwd, which will contain the authentication information for each of your accounts:
    [smtp.gmail.com]:587   username:password

    Add a line for each email address that needs to do SMTP authentication. (Update: Thanks, Bo, for the fix to this file.)

  6. 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:
    smtp.gmail.com:587			encrypt

    GMail requires the use of TLS, so the encrypt rule here ensures that Postfix will do TLS-based authentication when it connects.

  7. 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:

  1. Turn off Sendmail:
    service sendmail stop
  2. Start up Postfix:
    service postfix start
  3. 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

Enjoy!

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.

7 Comments

  1. Chuck

    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.

  2. 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…

  3. Paul,

    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’.

    Nice!

  4. Pingback: The Grand Fallacy » They love a good bandwagon.

Comments are closed.