Entropic Thoughts

Current Email Solution: gpg-agent, cron, OfflineIMAP, Notmuch, Alot, Vim and msmtp

Current Email Solution: gpg-agent, cron, OfflineIMAP, Notmuch, Alot, Vim and msmtp

I'm thinking of maybe replacing some parts in my current email pipeline, so I'm writing down the current state of things here lest I forget once I've made the switch. Hopefully this may also be of help to someone wanting something similar to what I have now.

I'll start by outlining the basic idea, and then I'll go slighly more in-depth about how each part is configured, and the problems that may arise.

Basic Idea

At some point a few years ago I had this idea that I wanted to start using email “for real”, whatever that means. Probably had to do with frequent correspondence, and maybe a sprinkle of mailing list in it too. (Spoiler alert: that never happened.)

As a step in that endeavour, I asked a friend to donate me an email inbox at his server. This is the email address you can see on my About page (). I also read up on how to efficiently deal with email locally on your machine. A common recommendation seemed to be sup – but! at the time that wasn't very actively maintained, which lead me to discover Notmuch.

Some things I like about Notmuch over sup is that Notmuch follows the Unix philosophy better by decoupling interface from indexing from downloading. All Notmuch does is index and search through your email. To get the other functionality associated with an email client (technical term: MUA, or Mail User Agent) you need to glue it together with additional software.

Here are the tasks normally associated with an email client:

  1. Download new emails (and synchronise "unread" flags and such).
  2. Filter all stored emails according to criteria.
  3. Display these relevant emails in a suitable view.
  4. Provide an editor to compose emails.
  5. Send away outgoing email to the outgoing mail server.

In a traditional email client, the same program might accomplish all of these. With my Notmuch setup, each of these tasks is accomplished by a separate program, which allows each program to "do one thing and do it well". These are the programs I use:

  1. Download emails: OfflineIMAP
  2. Filter emails: Notmuch
  3. Display emails: Alot
  4. Compose emails: Vim
  5. Send emails: msmtp

It works really well, and the reason I may change this is not because I'm discontent with it, but rather because I'm curious about what the grass is like on the other side. The primary change I'm interested in making is switching out Alot with Emacs instead, now that I'm slightly more comfortable with Emacs.

Let's get into details!

OfflineIMAP (and cron and gpg-agent...)

I run OfflineIMAP every five minutes as a cron job. Let's just see the configuration first. This is my .offlineimaprc, of course anonymised.

[general]
pythonfile = /home/john/.offlineimap.py
accounts = john@example.com

[Account john@example.com]
localrepository = Personal-local
remoterepository = Personal-remote

[Repository Personal-local]
type = Maildir
localfolders = ~/mail/john@example.com

[Repository Personal-remote]
type = IMAP
remotehost = imap.example.com
remoteport = 143
remoteuser = john
remotepasseval = get_pass('john.imap.example.com')

OfflineIMAP allows you to extend the application with your own Python code, which is what the pythonfile declaration says. In this file, I define the function getpass:

from subprocess import check_output
import os

def get_pass(mailbox):
    path = os.path.join(
        os.environ['HOME'],
        '.passwords',
        '{}.gpg'.format(mailbox)
    )
    gpg = [
        'gpg2', '--batch', '--no-tty',
        '--use-agent', '-dq', path
    ]
    return check_output(gpg).strip()

This uses gpg to decrypt the password, stored decrypted under ~/.passwords/john.imap.example.com.gpg. Why? Next section.

Obervations While Researching

I noticed two things while writing this part of the post. One is that apparently you don't need to run OfflineIMAP as a cron job. It can run as a daemon instead. Another is that the primary OfflineIMAP maintainer seems to have stepped down from developing OfflineIMAP. They are making security fixes and answering to pull requests, but they have themselves moved their own development efforts to a similar replacement project. I have not evaluated this alternative.

gpg-agent

I have an irrational dislike of specifying passphrases in plain text in configurations, so this is an additional twist to my configuration. I encrypt the password with gpg and then ask OfflineIMAP to decrypt it to be able to use it. I don't think that actually makes a difference given what I do next, but it gives me a nice, comfy, false sense of security.

Of course, this means OfflineIMAP will stop to ask me for my encryption passphrase every five minutes when it tries to download new mail, so I have to introduce gpg-agent, which lets me save the passphrase in memory so subsequent calls to gpg can use it without asking me.

I launch gpg-agent with gpg-agent --daemon --write-env-file which writes out the identifying information of the current agent to .gpg-agent-info. In the script that runs OfflineIMAP, I prepare this information by first calling

source /home/john/.gpg-agent-info

One thing worth noting is that by default, gpg-agent only saves passphrases in memory for something like five minutes, which would make it literally useless in this case. To tell it to hold onto keys for longer, I changed my ~/.gnupg/gpg-agent.conf to contain

default-cache-ttl 34560000
max-cache-ttl 34560000

As you may realise, this means the password I went to lengths to protect is very easy to get a hold of – either by connecting to the gpg-agent and decrypting the password, or perhaps directly by inspecting the memory contents of the machine. I tell myself that the kind of attacker I'm worried about is far more likely to snoop around for password-looking files on the filesystem than they are to attempt to decrypt files with the .gpg extension.

Of course, now that I've publically shared this process … I guess the little security by obscurity I had is gone.

Notmuch

Comparatively speaking, my Notmuch configuration is very spartan.

[database]
path=/home/john/mail

[user]
name=John
primary_email=john@example.com

[new]
tags=unread;inbox;

[maildir]
synchronize_flags=true

Did you click one of those Notmuch links and read about how great Notmuch is at tagging, managing threads, search, how you can include great spam filtering and so on? Well, I use nothing of that. I just haven't gotten around to starting to use email “for real”, so there hasn't been a need yet.

In the same cron script that runs offlineimap, I also run notmuch new to add any new email to my Notmuch database.

Alot

I have a lot of Alot configuration (see what I did there?), but 95% of it is just my theme, i.e. the colours I've picked for each element of the UI. The non-UI parts are these:

editor_cmd = vim

[bindings]
    q = bclose
    Q = exit

[accounts]
    [[john@example.com]]
        realname = John
        address = john@example.com
        sendmail_command = msmtp --account=john@example.com -t
        sent_box = maildir:///home/john/mail/john@example.com/Sent
        draft_box = maildir:///home/john/mail/john@example.com/Drafts
        [[[abook]]]
            type = shellcommand
            command = "notmuch address --output=recipients from:john@example.com"
            regexp = (\"?(?P<name>.+)\"?)?\s*<(?P<email>.*@.+?)>
            shellcommand_external_filtering = False

Here you also get a sneak peek on how to choose the editor for composing email, and the command used to send mail.

I'm not sure whether the sent_box and draft_box directories work like I want them to (i.e. get uploaded to the IMAP server, if that's even a thing), but I haven't bothered to look into it either.

Vim

Not much to say here (I'm on a roll!). Although my primary editor is Emacs, I'm a Vim fan. And Vim starts up a hell of a lot faster, so I opted to use Vim to compose email. I'm probably missing out on Emacs' message-mode, one of the reasons I'm thinking of switching.

msmtp (and gpg-agent)

To send email, I use msmtp, which at least at the time was the recommended drop-in replacement for sendmail. Like OfflineIMAP, it needs a password for the outgoing mail server, and like with OfflineIMAP, it can be coerced into taking that password in encrypted form. This is my configuration:

defaults
tls on
tls_certcheck off

account john@example.com
tls_starttls on
host smtp.example.com
port 587
from john@example.com
auth on
user john
passwordeval export $(cat /home/john/.gpg-agent-info) && gpg --use-agent --batch -q -d ~/.passwords/john.smtp.example.com.gpg

As you can see, the passwordeval directive allows some sort of shell script to be run to get the password, which in this case is a gpg decryption command. The same caveats about gpg-agent as in the OfflineIMAP section applies.

The Replacements

But Chris, this all sounds wonderful. Why on earth would you want to switch anything of this out?

I'm not quite sure. I'm always thinking "surely this will get me to use my email more, if I just install this new shiny toy". I know it doesn't work that way. I can't help thinking it though.

The shiny new toy I'm currently looking at is message-mode in Emacs to compose email. I do it very manually at the moment. I also like the prospect of using an Alot replacement that is actually developed by the same people that are making Notmuch. The slow start-up times of Emacs won't actually matter if I'm in Emacs already anyway!

I'm also curious about adding some sort of automatic spam filtering and tagging solution, to actually start playing to the strengths of Notmuch.