I have tried to get my mail in the traditional Unix way, with an MTA, MDA, MRA, MUA, all that stuff. It was a huge pain. With some more modern programs, though, I can have a setup that still follows the Unix philosophy of single-purpose programs working together, while being a lot easier to understand.

There are four main programs in my setup:

offlineimap

offlineimap connects to the IMAP servers for my gmail and self-hosted mail accounts and downloads any new mail, according to its account, into a subdirectory of ~/mail/, in Maildir format.

I also use this offlineimap-notify script, which just wraps offlineimap to pop up notifications when new mails are downloaded. As expected, these notifications are sent over D-Bus, and are displayed by a daemon which follows the Desktop Notifications Specification. (I use dunst.)

offlineimap is configured to run notmuch new when it finishes syncing. If notmuch changes anything in the mail directories, offlineimap will sync it back to the IMAP servers. This means read-status, folder location, deletion-status, etc. are synced back to the IMAP servers and available to other clients (like my phone).

notmuch

notmuch indexes the email living in the subdirectories of ~/mail/ and allows for fast search and tagging over them. It’s implemented on top of xapian, a text indexing and searching library. When notmuch new is run, notmuch inspects the directories it’s responsible for indexing and adds any new mail that’s appeared there to the index. Since read-status, folder location, and deletion-status are present in the Maildir format, notmuch also adds appropriate tags to represent this information internally. Then, notmuch search tag:inbox will show all the mail in my inbox, and notmuch search "tag:inbox tag:unread" will show all the unread mail in my inbox.

alot

When first opened, alot runs notmuch search "tag:inbox AND NOT tag:killed" and displays the results. I can navigate the results with vi-style bindings, open a specific email, and look through all the emails in that thread.

I can also compose and send mail. Composition of mail starts with alot generating a mostly-blank temporary file, with the contents depending on whether I’m sending a new mail or replying to an existing one (in the latter case, it will automatically include and quote the existing mail). As is typical, alot then runs $EDITOR tempfile, so I can compose my mail in vim or Emacs or whatever I please. When I close my editor, the updated file appears in alot, and I can add attachments or reopen my editor to do more edits. When I hit send, the file is passed to msmtp, which reads the headers to learn To, From, etc.

I also use nottoomuch-addresses.sh to get contacts tab-completion when beginning to compose an email. This builds up a database of contacts from my notmuch index. This is a stop-gap solution for me, I hope. I’d rather use the contacts in my CardDAV account, provided by ownCloud, but this database is currently close to empty. Thus I may switch over to using pyCardDav for contacts completion at some point.

msmtp

msmtp connects to the configured SMTP server to send the email. With multiple configured accounts, it chooses the account and corresponding server based on the provided “From” address.

msmtp provides sendmail emulation. sendmail is very frequently executed by other programs that wish to send mail. So sometimes I use the command-line program mail, from s-nail, to send small emails or attachments, since it just calls out to sendmail Likewise when I started toying with kernel development, git send-email worked out of the box, and when I tried sending mail from Emacs, it also worked with no setup. I’m sure I’ll run into other Unix utilities that also invoke sendmail, and pleasingly work with no additional configuration thanks to my use of msmtp.