Reading emails in Mutt


This is a post about configuring your command line environment to let you read e-mails in Mutt. Sorry for small assumption. I write for people familiar with SSH, with some knowledge of key agents, able to edit in Vim and so on. No need to know how to read emails in Emacs or write your own OS kernel.

The benefits of this e-mail client configuration are:
  1. access from everywhere, only terminal and SSH client required
  2. fast browsing, no graphics, loading, rendering and similar stuff
  3. full text search
  4. deep customization - flexibility of Mutt and associated utilities
This is going to be updated from time to time, or I'll add new posts about different components of the configuration, so stay tuned.


First, I need the source of e-mails. If you read directly on the server where exim or postfix work as SMTP servers, you can skip the IMAP stuff.

To make the search of e-mails really fast in full-text search mode, we need to download all e-mails locally and index them. We use IMAP protocol to fetch them. Before we fetch, we make some sorting on server side. This is what I usually do locally with procmail.
There is a helper, that makes it all possible to publish without disclosing my password: GnuPG.


I start GnuPG agent without any magic - from bashrc:
export GPG_TTY=$(tty)
if [[ ! -f $HOME/.gnupg/S.gpg-agent ]]; then
    gpg-agent \
    --use-standard-socket \
    --daemon \
    --verbose \
    --write-env-file $HOME/.gpg-agent-info \
    --log-file $HOME/local/var/log/gpg-agent.log \
    --pinentry-program /usr/bin/pinentry-curses \
    --default-cache-ttl 28800 \
    --max-cache-ttl 288000 > /dev/null
eval $(cat $HOME/.gpg-agent-info)
Remeber, the TTL periods above are pretty long and this makes all the system more convenient, but less secure. Adjust to meet your needs.
Then you can generate new key, if you do not have any. zacharyvoase describes it pretty well. Get your key number, if you do not have it written down:
gpg2 --list-keys

Password storage

Install also tree and other dependencies from README.
make test # it failed in some cases, but app works perfectly
pass init YOUR_GPG_KEY
pass insert gmail_or_whatever
pass gmail_or_whatever
Should ask for a password to GPG keyring, and keep it for 8 hours (if do not ask again in that time).


To sort e-mails locally, Mutt could not help me. I wanted to do it before fetching and synchronize already sorted folders. I took IMAPfilter to do the job. The configuration for IMAPfilter is located in ~/.imapfilter/config.lua. I needed to add the following code to convince IMAPfilter to ask gpg-agent:
myuser = 'your_imap_login'
local cmd = 'FULL_PATH_TO/pass pass_description'
local fd = io.popen(cmd, 'r')
pass_string = fd:read("*a")
mypass = pass_string:sub(0, -2)

IMAP synchronization

This is job for offlineIMAP. Its written in Python and configuration is in the same language. So some knowledge in this matter can help, however there are many tutorials and examples how to make it work some common scenarios.


Full text search

OfflineIMAP offers a hook that can trigger mail indexer. I am using not-much, which relies on Xapian. Its invoked this way:
postsynchook = FULL_PATH_TO/notmuch new
in [Account] section.


 To give Mutt an interface to notmuch, a Python script was created. My version is available on GitHub.


I installed so called "patched" version of Mutt, that one with the side panel.
The main things that are here to adjust:
  • basic stuff like folders, mailboxes, names, addresses
  • some helpful macros (search)
  • scoring
  • highlighting
  • keys binding to make Mutt more similar to Vim
  • HTML rendering