Kevin's Mutt Tips and Tricks

Patches for Mutt

My patches to mutt are on this page.


These are a few suggestions for how I like to do things in mutt. I hope someone will find them useful.

I primarily use FastMail for my email provider. (I have a Gmail address too, but am migrating away from it. These profile tips are thus kept here more to help others than myself now.)

I also like to use mutt whenever possible, as it's fast, keyboard driven, standards compliant, and integrates GPG (not to mention I'm a committer now!). In order to be able to use mutt with multiple accounts, I have my own method of implementing profiles.

Profiles in Mutt

There are many ways to implement "profiles" in mutt. (By profiles, I mean a group of settings specific to an email account). A quick google search will show many "helper" programs and hooks used to toggle between settings within a single running instance of mutt.

The problem with all these is that mutt wasn't designed with profiles in mind. You have to be extremely careful one profile doesn't bleed over into another as you switch between them.

I have several accounts I like to check with mutt: gmail, fastmail, and spool. I use a much simpler way of managing them: shell aliases that source a different custom muttrc, along with a single "common" muttrc file. An example will probably make this clearer. My .zshrc file contains the aliases:

alias mutt='LOCAL_CONFIG=spool /usr/bin/mutt'
alias mutt-fastmail='LOCAL_CONFIG=fastmail /usr/bin/mutt'
alias mutt-gmail='LOCAL_CONFIG=gmail /usr/bin/mutt'

In my .mutt/muttrc file, the last line uses the environment variable set by each alias to load a custom config file:

source ~/.mutt/muttrc.local.$LOCAL_CONFIG

The main .mutt/muttrc file contains generic settings I prefer across all my mutt profiles:

unset arrow_cursor         # use arrow cursor
unset askbcc               # don't prompt for bcc's
unset askcc                # don't prompt for cc's
unset beep                 # don't beep on error
unset beep_new             # don't beep on new message
set   bounce_delivered     # unset: remove Delivered-To: when bouncing?
unset collapse_unread      # don't collapse threads with unread mails
set   uncollapse_jump      # jump to unread message when uncollapse
set   confirmappend        # may want to change this later
set   copy                 # save copies of sent messages
set   delete               # don't ask me to delete messages - just do it!
set   edit_headers         # display the headers when I'm editing a message
set   fast_reply           # don't prompt for stuff when replying
set   followup_to          # add Mail-Followup-To header
set   help                 # show help on first line of display
unset mark_old             # don't mark unread messages as Old
unset menu_scroll          # scroll menu a page on last line
set   narrow_tree          # narrow threading trees
set   pager_stop           # don't go to next message at end of message
source ~/.mutt/muttrc.local.$LOCAL_CONFIG

Then, each muttrc.local.[profile] file can contain specifics for connecting and sending mail for that account. Here are my settings for fastmail, in the file .mutt/muttrc.local.fastmail:

set my_user=foo
set my_pass=bar

set record="imaps://$my_server/INBOX.Sent Items"
set postponed="imaps://$my_server/INBOX.Drafts"

# This is who I am
set from="XXXX@XXX.XX"

# IMAP settings

# Header caching directory
set header_cache=~/.mutt/hcache/fastmail

# SMTP server to relay to
# NOTE: to get this to work, I had to install the libsasl2-modules package
set smtp_url="smtp://$my_user:$my_pass@$my_smtp_server:587/"

# Slow down over imap
set mail_check=300               # How often to check in seconds

set imap_user=$my_user
# set imap_pass=$my_pass

# Default inbox
set spoolfile=imaps://$my_server/INBOX

# Default location of mailboxes
set folder=imaps://$my_server/INBOX

# Mailboxes to monitor for mail
# (arranged in urgency reading order)
mailboxes imaps://$my_server/INBOX

# high
mailboxes imaps://$my_server/
mailboxes imaps://$my_server/
mailboxes imaps://$my_server/INBOX.baz


The setting for are similar, with just the different accounts, passwords, smtp servers, etc for that account. Here is an example for gmail.

Combined with gnu screen, I can easily flip between different accounts, launching mutt-fastmail in one shell, mutt-gmail in another, etc. It's simple to manage and works well for me.

Mutt profiles and GNU Screen

I have a command set up called screen-mail. This runs:

screen -S mail -c ~/screen/mail.screenrc

Inside ~/screen/mail.screenrc:

source $HOME/.screenrc

screen -t fastmail zsh -i -c mutt-fastmail

screen -t gmail zsh -i -c mutt-gmail

screen -t spool zsh -i -c mutt

screen -t oi zsh -c '$HOME/bin/; zsh -i'

screen -t newsbeuter newsbeuter

This launches all my mutt instances, along with offlineimap, in one go. I added a zsh invocation after offlineimap so that I don't lose the screen window when I exit offlineimap (or it crashes).

Those paying attention (or who just haven't fallen asleep) will have noticed my above mutt profile examples use imap directly and here I'm using offlineimap. I actually have an IMAP and a local offlineimap based profile for each: mutt-gmail-imap and mutt-gmail, mutt-fastmail-imap and mutt-fastmail. By default right now I'm using offlineimap and the local profile. But it's easy this way to launch a new screen window and run mutt-fastmail-imap if I want to directly connect using imap for some reason.

offlineimap and lbdb (m_inmail)

I use lbdb to query several different sources for my address book. One of those is m_inmail, which is populated from the mails I receive.

Most sites say to run lbdb-fetchaddr through procmail, adding them as you receive emails. But this isn't practical over IMAP or when using offlineimap. Instead, I use a cron job to find recent emails and add them.

One of the difficulties in doing this is that each email has to be piped to the 'lbdb-fetchaddr' command, which is not so easy to do via find. My solution is below:


find /home/kjm/Mail/fastmail/INBOX -type f -mtime -7 -print0 | \
  xargs -0 -n 1 -r /bin/bash -c 'lbdb-fetchaddr -a < "$1"' lbdb-fetchaddr

find /home/kjm/Mail/gmail/INBOX -type f -mtime -7 -print0 | \
  xargs -0 -n 1 -r /bin/bash -c 'lbdb-fetchaddr -a < "$1"' lbdb-fetchaddr

# remove dups
SORT_OUTPUT=name /usr/lib/lbdb/lbdb-munge

This uses a few clever tricks. The find/xargs invocation is pretty standard, but here we add the flag '-n 1' to invoke the command with one argument at a time. The '-r' prevents the command from running if no results are found.

The invocation of the shell by xargs is most interesting. xargs by default will append the file to the command. However, the bash man page says: If there are arguments after the string, they are assigned to the positional parameters, starting with $0. The 'lbdb-fetchaddr' at the end is $0 for the command, and the email file will be $1 (appended by xargs). So this essentially tricks xargs into giving us the file as stdin, (via the sh -c 'mycmd < $1' arg0 arg1 construct).


I am now using FastMail for my mail and address book. I highly recommend the pyCardDav project to sync FastMail's addresses locally. It works directly from mutt, and is easily used with lbdb too. Just create a file in ~/.lbdb/modules/m_pycard:



m_pycard_query ()
    /usr/local/bin/pc_query -m "$@" | grep -v '^searching for' | sed -e 's/$/ - pycard/'

Then just add "m_pycard" to your METHODS in your ~/.lbdb/lbdbrc file.