A Fusion of Mutt, Gmail, Offlineimap, msmtp, and PGP
Email clients suck, Mutt just sucks less (yes I did rip off their slogan). There are tons of email clients out there, most of which really do suck badly. I used the Gmail client for some time and it was OK, for a web client. I could have used sane thread handling, actually showing email that got sent to myself, S/MIME or PGP support (preferably PGP), not having to fire up resource heavy firefox, etc etc. Now let me preface this by saying that Mutt is not for everyone. It is a terminal based client, making it great for ssh, and it has a very steep learning curve. One mistake people commonly make is that they assume that, like most other email clients, Mutt handles receiving, sending and viewing email. This is an incorrect assumption as mutt is solely a MUA (Mail User Agent). The idea is that you piece together exactly how you want your email system to work. This means that it requires a lot of work on the users end to configure the system, although it does afford the advantage of having an email setup that does exactly what you want it to do, exactly how you want it done.
With that being said, I will first explain in words what my setup is, how it works, and why it makes sense to do it this way…then I will include all relevant configuration files along the way.
So I have Mutt, and my massively customized .muttrc. It includes where my folders are located, how I want key bindings to behave, colors, PGP settings, key bindings hooks for sending from the appropriate addresses, how i want to edit and view my headers, that I want to use vim to edit email, how email threads should look, blah blah blah. Below is my muttrc in all of its glory. I have painstakingly commented all the relevant pieces so everything makes sense to the normal person (and to me when I forget what stuff does. I have excluded certain pieces to avoid getting spammed :p )
set mbox_type = Maildir
set mbox = "~/mail/gmail"
set folder = "~/mail/gmail"
set spoolfile = +INBOX
set postponed = +drafts
set trash = +trash # special folder. you will need the trash patch
folder-hook . 'set record = ^' # store sent mail in the same folder as sent from
set header_cache =~/.mutt/cache/headers
set tmpdir = ~/.mutt/temp
set mailcap_path = ~/.mailcap
set hostname = behemoth.al3k.net
set timeout = 3 # idle time before scanning
unset beep # stop beeping at me
alternates (a regex that includes all of the email address you send and receive mail to/froma>)
# Header related stuff
ignore * # ignore everything
unignore From: To: Cc: Date: Subject: # only unignore stuff i want to see
unignore x-mailer: x-pgp-key: posted-to: # only unignore stuff i want to see
unignore User-Agent: # only unignore stuff i want to see
hdr_order From: To: Cc: Date: Subject: # the order I want the unignored stuff to display
my_hdr X-PGP-Key: http://opensource.osu.edu/~al3k/pubkey.asc
# composing stuff
set realname = "Alek Rollyson" # set my name
set edit_headers # include headers when editing
set fast_reply # skip to composing when replying
set reply_to # reply to Reply to: field
set include # include messages in replies
set forward_quote # include messages in forwards
set attribution = "On %d, %n wrote:" # set the attribution
unset mime_forward # include attachments as part of the body
set sig_dashes = yes # dashes in my siggy
set sig_on_top # put my signature before the forwarded message
set askcc # ask for CC:
set forward_format = "Fwd: %s" # format for subject when forwarding
set use_envelope_from # make sure From: and the smtp sender match up
set ispell = "aspell -e -c" # use aspell as ispell
set sendmail_wait = "-1" # Don't wait for sendmai;
set user_agent # show people i'm using mutt!
set copy = yes # keep sent messages
# Sorting, Markers etc.
set display_filter = mail-to-filter # cuts off long to: lines
#set implicit_autoview # figure out autoview stuff automatically. stupid html mail
alternative_order text/plain text/html # don't prefer html over plain text
unset move # gmail does that
set delete # don't ask to delete, just do
unset confirmappend # don't ask to append, just do!
set quit # don't ask to quit, just do!!
unset mark_old # don't mark as old, it's pointless
set tilde # pretty tildes in the pager like vim
set markers=no # don't put '+' at the beginning of wrapped lines
set pager_index_lines= 20 # how large is the index window?
set pager_stop # don't automatically go to the next message
set menu_scroll # scroll in menus
set sort = 'threads' # thread style
set sort_aux = 'reverse-last-date' # secondary sorting after threading. gmail-like
set sort_browser='reverse-date' # fixes the way thread sorting handles dates, makes more sense
#set nostrict_threads # fuzzy threading. don't always group like subjects
# Vim!
set editor= "vim +:silent+/^$" # use vim and skip to the first blank line
# random macros and bindings. adding vim things and bindings for external programs
bind pager gg top
bind pager G bottom
bind pager,index K previous-undeleted
bind pager,index J next-undeleted
bind pager,index j next-entry
bind pager,index k previous-entry
bind index,pager R group-reply
bind index B bounce-message
set query_command = "abook --mutt-query '%s'"
bind editor complete-query
bind editor ^T complete
macro index,pager Z "!offlineimap -q -o -u Curses.Blinkenlights\n" "invoke offlineimap" << this may be useless since I now daemonize offlineimap
macro generic,index,pager \Ca "abook" "launch abook"
macro index,pager A "
abook --add-email" "add sender to abook"
macro pager,index I "!" "go to Inbox"
# macros to source profiles for different email addresses
macro index,pager ":source ~/.mutt/profile.gmail\n"
macro index,pager ":source ~/.mutt/profile.al3k\n"
macro index,pager ":source ~/.mutt/profile.arollyson\n"
macro index,pager ":source ~/.mutt/profile.matrix\n"
macro index,pager ":source ~/.mutt/profile.opensource\n"
macro index,pager ":source ~/.mutt/profile.osu\n"
# teh source!
source ~/.mutt/autoview # autoview stuff for mailcap
source `FILE=$HOME/.mutt/sidebar; mutt -v | grep -Fq sidebar || FILE=/dev/null; echo $FILE` # conditionally source sidebar
source ~/.mutt/profile.gmail # default profile to source
source `FILE=$HOME/.mutt/colors; [[ $TERM =~ 256 ]] && FILE=$HOME/.mutt/256colors; echo $FILE` #conditionally source 256 colors
source ~/.mutt/subscriptions # Define the list of subscribed mailing lists.
source ~/.mutt/gpg # gpg stuffs
# reply hooks to send from correct addresses
reply-hook "~C ()$" source ~/.mutt/profile.matrix\n
reply-hook "~C ()" source ~/.mutt/profile.osu\n
reply-hook "~C ()" source ~/.mutt/profile.arollyson\n
reply-hook "~C ()" source ~/.mutt/profile.gmail\n
reply-hook "~C (
)" source ~/.mutt/profile.al3k\n
reply-hook "~C ()" source ~/.mutt/profile.opensource\n
I use vim as my email composer and there are a few tricks to get vim to play well with mutt. Here is a snippet from my vimrc that enables spellchecking for mutt files and a few key bindings to may my mail look pretty when I’m done slapping on my keyboard.
au BufRead ~/.mutt/temp/mutt* set spell " <-- vim 7 required
au BufRead ~/.mutt/temp/mutt* nmap <F3> gqap
au BufRead ~/.mutt/temp/mutt* nmap <F4> gqqj
au BufRead ~/.mutt/temp/mutt* nmap <F5> kgqj
au BufRead ~/.mutt/temp/mutt* map! <F3> <ESC>gqapi
au BufRead ~/.mutt/temp/mutt* map! <F4> <ESC>gqqji
au BufRead ~/.mutt/temp/mutt* map! <F5> <ESC>kgqji
augroup END
Pretty self explanatory if you’re familiar with vim. Enables spellchecking for mutt composition and gives me F3 – F5 for nice paragraph formatting.
As far as the F key mappings and reply hooks go, this is how I send from multiple addresses in Mutt easily. Whenever I want to send as a certain address I just hit the corresponding F key from within mutt and then go on composing merrily. The reply hooks ensure that I always reply as the address the email was addressed to. Reply hooks essentially work the same as send-hooks except backwards. They are not very well documented in the Mutt manual, which is a shame because they are extremely useful in cases like this. The F keys source profiles that I have in my .mutt folder, they all must identical (except for different values in the variables of course) since they are sourcing out the same information. Here is a skeleton profile that I use:
# Signature file
set signature='~/.mutt/signature-al3k'
#smtp settings
set sendmail='/usr/bin/msmtp -a al3k'
# Customized headers
set from="al3k@al3k.net"
# Include the profile name in the status line
set status_format="-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b? %?l? %l?]---(%s/%S)-al3k-%>-(%P)---"
As you can see, each profile contains a path to the correct signature for that profile, setting the “send from” variable, passing the correct arguments to msmtp (which will be covered later), and setting the status bar to show which profile I am actually using…in this case al3k is the profile. The default profile sourced is set in my muttrc (see above) and I can switch them out at will by hitting F7 through F12 in Mutt.
Now this is how I view and compose mail, sending and receiving is a different story; I will begin with how I receive my email. Bottom line, offlineimap is awesome. I realize Mutt has built in imap support, but it is mega slow and I would rather have a local copy anyways. From the offlineimap project github site, “You get a current copy of your messages on each computer, and changes you make one place will be visible on all other systems. For instance, you can delete a message on your home computer, and it will appear deleted on your work computer as well. OfflineIMAP is also useful if you want to use a mail reader that does not have IMAP support, has poor IMAP support, or does not provide disconnected operation.” The one downside to this is that it’s tough to find a solution to store your passwords in a secure way. For now I just store them directly in the file as I have an encrypted disk. In the future I would like to whip up a simple python keyring to store these safely, gnome-keyring and kwallet are waaaay too bloated for me to feel worth using them. Here is my .offlineimaprc
accounts = Gmail
ui = Noninteractive.Quiet
maxconnections = 3
[Account Gmail]
localrepository = mylocal
remoterepository = Gmail
autorefresh = 5
quick = 10
[Repository mylocal]
type = Maildir
localfolders = ~/mail/gmail
[Repository Gmail]
type = Gmail
remoteuser = yea...
remotepass = hah!
ssl = yes
realdelete = no
folderfilter = lambda foldername: not re.search('.*All Mail$', foldername)
nametrans = lambda folder: re.sub('.*Spam$', 'spam', re.sub('.*Drafts$', 'drafts', re.sub('.*Sent Mail$', 'sent', re.sub('.*Starred$', 'flagged', re.sub('.*Trash$', 'trash', folder)))))
Just insert your username and password where needed and chmod 0600 the file. The nametrans function just uses a regex to translate the goofy gmail virtual folders into names that actually make sense. Feel free to change the names of localrepository and whatever else, just my setup…doesn’t have to be yours.
The, I use this short script stolen from the Arch Linux wiki to quickly daemonize a program that i place in ~/build/start_daemon (offlineimap occasionally crashes and becomes a resource hog, this takes care of that problem):
set -e -f -u
while getopts n:c:p: f; do
case $f in
n) NICE=$OPTARG;;
c) IONICE_CLASS=$OPTARG;;
p) IONICE_PRIORITY=$OPTARG;;
*) exit 2;;
esac
done
shift $((OPTIND - 1))
cmd=$*
if ! pgrep -u "$UID" -xf -- "$cmd" >/dev/null 2>&1; then
nice_args=
ionice_args=
var2arg() {
if [ -n "$3" ]; then
eval "$1=$2\ $3\ \$$1"
fi
}
arg2cmd() {
if [ -n "$2" ] && type "$1" >/dev/null 2>&1; then
cmd="$* -- $cmd"
fi
}
var2arg nice_args -n "$NICE"
var2arg ionice_args -c "$IONICE_CLASS"
var2arg ionice_args -n "$IONICE_PRIORITY"
arg2cmd nice "$nice_args"
arg2cmd ionice "$ionice_args"
exec $cmd
fi
And then set up a cron job to run this every five minutes:
Ta da! offlineimap is syncing your local copy of your inbox with gmail every 5 minutes, all changes made at any point will be reflected everywhere, plus you have an offline copy of your inbox to work with!
For sending mail, I use the lightweigh msmtp and it works awesomely for me. You saw above that each profile sets the sendmail command, which is smtp followed by the argument -a and the name of the profile. This makes it extremely easy to send from different smtp servers and email addresses at will. Here is a skeleton .msmtprc that is similar to the one I use:
defaults
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/logs/msmtp.log
# GMAIL
account gmail
host <one of my smtp servers>
port 587
from <one of my email addresses>
domain <domain of the email address
auth on
user <username for the server>
password <password for the server>
# arollyson
account arollyson
host <one of my smtp servers>
port 587
from <a different email addresses>
domain <domain of the different email address
auth on
user <username for the other server>
password <password for the other server>
With that setup you can send from the different accounts via msmtp -a <accountname>, works pretty well for me.
As far as PGP signing/encrypting goes, it’s rather simple as well. I borrowed a piece of configuration from another guy who was nice enough to write about his mutt setup and combined it with some gnupg configuration to get a very nice PGP + mutt combination. As you can see above in my .muttrc I source a file called ~/.mutt/gpg which contains all of my gpg settings and looks like so…
# the string "PGPPASSFD=0" if one is needed.
#
# This is mostly used in conditional % sequences.
#
# %f Most PGP commands operate on a single file or a file
# containing a message. %f expands to this file's name.
#
# %s When verifying signatures, there is another temporary file
# containing the detached signature. %s expands to this
# file's name.
#
# %a In "signing" contexts, this expands to the value of the
# configuration variable $pgp_sign_as. You probably need to
# use this within a conditional % sequence.
#
# %r In many contexts, mutt passes key IDs to pgp. %r expands to
# a list of key IDs.
# decode application/pgp
set pgp_decode_command="gpg %?p?--passphrase-fd 0? --no-verbose --batch --output - %f"
# verify a pgp/mime signature
set pgp_verify_command="gpg --no-verbose --batch --output - --verify %s %f"
# decrypt a pgp/mime attachment
set pgp_decrypt_command="gpg --passphrase-fd 0 --no-verbose --batch --output - %f"
# create a pgp/mime signed attachment
set pgp_sign_command="gpg --no-verbose --batch --output - --passphrase-fd 0 --armor --detach-sign --textmode %?a?-u %a? %f"
# create a application/pgp signed (old-style) message
set pgp_clearsign_command="gpg --no-verbose --batch --output - --passphrase-fd 0 --armor --textmode --clearsign %?a?-u %a? %f"
# create a pgp/mime encrypted attachment
set pgp_encrypt_only_command="/usr/lib/mutt/pgpewrap gpg -v --batch --output - --encrypt --textmode --armor --always-trust -- -r %r -- %f"
# create a pgp/mime encrypted and signed attachment
set pgp_encrypt_sign_command="/usr/lib/mutt/pgpewrap gpg --passphrase-fd 0 -v --batch --output - --encrypt --sign %?a?-u %a? --armor --always-trust -- -r %r -- %f"
# import a key into the public key ring
set pgp_import_command="gpg --no-verbose --import -v %f"
# export a key from the public key ring
set pgp_export_command="gpg --no-verbose --export --armor %r"
# verify a key
set pgp_verify_key_command="gpg --no-verbose --batch --fingerprint --check-sigs %r"
# read in the public key ring
set pgp_list_pubring_command="gpg --no-verbose --batch --with-colons --list-keys %r"
# read in the secret key ring
set pgp_list_secring_command="gpg --no-verbose --batch --with-colons --list-secret-keys %r"
# receive key from keyserver:
set pgp_getkeys_command="gpg --recv-keys %r > /dev/null 2>&1"
# automatically sign outgoing mail
set pgp_autosign = yes
# half hour timeout
set pgp_timeout = 1800
# always verify sigs
set pgp_verify_sig = yes
#what to say when a good sig occurs
set pgp_good_sign = "^gpg: Good signature from"
# unset this crap, stop doing it!
unset crypt_autosmime
I know that just looks to be a bunch of jibberish but I do promise that it does work. The setup is generic and should work for anyone, I won’t bother explaining it since I feel it is well commented but the short version is that Mutt just needs to be spoonfed the commands it needs to perform PGP actions on email. This, in conjunction with a few settings on your .gnupg/gpg.conf, will make Mutt a secure email machine. Here’s the relevant pieces you will want:
keyserver-options auto-key-retrieve
#encrypt-to-self - allow you to read messages you encrypted for others
#use 'gpg --fingerprint' to get this value - just remove the spaces
encrypt-to <insert your pgp fingerprint here>
Pretty simple, all this does it set what public keyserver you want to use, MIT is extremely popular and I’m pretty sure they all propagate to each other anyway, and will automatically retrieve public keys when you receive mail from someone who stores their key on the server(s) as well. The last line will automatically sign all encrypted messages to yourself as well as the recipient so you don’t get encrypted out of your own sent email :p
Lastly is my coloring, but that is really just a matter of taste. I use 256 color profiles as well so it may not be compatible with everyone’s setup. I’ll go ahead and post my colorscheme here and a screenshot, but that pretty much makes covers everything I do in Mutt. I have yet to work on getting a real good mailcap going so I don’t have anything worthwhile to post here, but I will check back in when I have something worth sharing.
Here’s my color setup:
color normal white default
# main colors
color status brightwhite blue
color indicator brightyellow red
color tree brightmagenta default
color error brightred default
color message brightyellow default
# uncolor everything, only recolor what i want
#uncolor index *
# and recolor them appropriately
color index color69 default ~u
color index color240 default ~P
color index brightyellow default ~N
color index brightgreen default ~T
color index brightred default ~D
# set up the headers
color header brightred default "^from:"
color header yellow default "^to:"
color header yellow default "^cc:"
color header color69 default "^date:"
color header color69 default "^subject:"
color header brightcyan default "^user-agent|^x-*"
# message bodies
color attachment brightred default
color search red brightred
color signature cyan default
color tilde blue default
# urls
color body brightmagenta default "(^|<| )mailto:[^ ]+@[^ ]( |>|$)"
color body brightmagenta default "(^|<| )(http|https|ftp|file|telnet|news|finger)://[^ ]+( |>|$)"
# smileys, the right way and the backward-ass euro way
color body color172 default "(^| )+(|[<>|])[8;:](|[^ ])[)(/|DOPS]( |$)+"
color body color172 default "(^| )+[)(/|DOPS](|[^ ])[8;:](|[<>|])( |$)+"
# *bold*, _underline_, and /italic/
color body brightcyan default "(^| )\\*[^ ]+\\*( |$)"
color body brightcyan default "(^| )_[^ ]+_( |$)"
color body brightcyan default "(^| )/[^ ]+/( |$)"
# quote blocks
color quoted magenta default
color quoted1 cyan default
color quoted2 green default
color quoted3 magenta default
color quoted4 cyan default
color quoted5 green default
color quoted6 magenta default
color quoted7 cyan default
# PGP messages
color body brightgreen default "^gpg: Good signature .*"
color body white default "^gpg: "
color body brightwhite red "^gpg: BAD signature from.*"
And here’s a few screenshots of my Mutt in action. Excuse the crappy pictures, I was on my Mac (not by choice) at the time and I personally think the console looks cartoony as hell. I’ll get some better ones up later.
Here is how my full setup looks, in fancy gallery fashion.
Hope this helps out people looking to get a jump start on mutt, or those looking for some more advanced tweaks to make mutt more awesome than it already is. Leave a comment if you have any questions, or really just anything to say.




