The Devil is in the Email, Mutt Guide Pt. 1
Jun 14, 2018
I’ve had many false starts with Mutt. It’s probably the piece of software I’ve had the most trouble getting into. Yes, more than Vim or Emacs. It’s not even Mutt’s fault really, I think the main culprit is that I always followed the examples and guides of people heavily focused on setting up an incredibly robust system with separate IMAP and SMTP setups. Some even add on custom filtering and tagging. It doesn’t help that many of these guides operate under the guise of a beginner’s guide.
I don’t want to sound like I’m condemning these excellent resources. There is nothing wrong with such a robust setup. It is after all the setup I wanted and one I eventually achieved after weeks of tinkering. Most of my problems getting started with Mutt are probably my own fault. The ArchWiki has an excellent starters guide but I’m probably too ambitious and jumped right ahead into trying to setup the fully featured, robust setup of my dreams and consequently would get a little confused and disheartened.
In this article I’ll be going through my personal journey setting up Mutt to meet my needs and explain my reasoning behind why I did certain things the way I did.
Table of Contents
I Started out with Nothing, and I Still Got Most of It Left
My initial setup is one where Mutt handles (to the best of its capabilities) everything I need. The robust setup with separate external IMAP, SMTP and tagging capabilities as well as a local copy of all my mail will come later. Got to start small.
The Beginnings
After having not touched Mutt for almost a year, this reddit post got
me interested in trying Mutt again and building my own solution piece
by piece just like I did in Vim. So I modified it slightly and this is
what I started with in my $HOME/.mutt/muttrc
:
set folder = "imaps://imap.gmail.com" set imap_user = "bassam.saeed@gmail.com" set imap_pass = `pass mail/gmail/mutt` set smtp_url = "smtps://bassam.saeed@gmail.com@smtp.gmail.com" set smtp_pass = `pass mail/gmail/mutt` set realname = "Bassam Saeed" set from = "bassam.saeed@gmail.com" set header_cache = "~/.mutt/cache/headers" set message_cachedir = "~/.mutt/cache/bodies" set spoolfile = "+INBOX" set postponed = "+[Gmail]/Drafts" set trash = "+[Gmail]/Trash"
This is a bare bones configuration but it should be enough to get most people at least started with Mutt.
Most of this should be fairly self-explanatory. The folder
setting
defines the default location of the mailbox. Because I’m not keeping a
complete copy of all my mail locally, the setting is set to just use
the Gmail IMAP server. The header and message caches are there so I
don’t have to re-download them every time I start up Mutt. I consider
the header cache pretty mandatory but some people may not need the
message cache. The spoolfile
is where unfiltered email arrives. In
Gmail (and most email providers) this is known as the INBOX so you can
define that relative to the default mailbox by putting a +
in
front. The postponed
and trash
settings are defined under
[Gmail]. Other email providers will have it somewhere else.
I use the excellent pass utility as my password manager and so I allow
Mutt to run this command for IMAP and SMTP authentication by using
grave accents (backticks) to query pass
for the Gmail password.
Note: I have two-factor authentication enabled for my Google accounts and so I needed to create a separate App Password for use with Mutt.
Growing Pains
There are a couple of things I realized quickly were less than ideal with my initial setup. In fact within a couple of minutes I had added the following setting:
set sort = reverse-date-received
For better or worse I’ve spent my whole life using email clients where the newest email (received or sent) was at the top of the list. Mutt’s default of it being on the bottom is completely anathema to me. So I changed it almost immediately.
My primary Gmail account is linked with multiple other Gmail accounts. So I needed a way to choose which account I was sending mail as:
set edit_headers = yes
Unholy Emails
Unfortunately in the world we live in, people love to send html emails. Some will by courteous enough to include a plain text version but many wont. The good news is that there are a decent number of command-line browsers that can convert html to plain text within Mutt itself.
First you have to define which browser to use in the mailcap
file. By
default Mutt looks in $HOME/.mailcap
for this file but I prefer
keeping everything in the $HOME/.mutt
directory so I changed the
default mailcap path.
set mailcap_path = "~/.mutt/mailcap"
For my browser I settled on elinks but most console browsers should work just fine.
text/html; elinks -dump; copiousoutput
The copiousoutput
tells Mutt to we’re potentially passing large
amounts of text and so Mutt invokes a pager. By default this is Mutt’s
internal pager but you can define an external one using the pager
setting in your muttrc
.
Now I tell Mutt how to actually handle these files by putting the
following in my muttrc
.
alternative_order text/plain text/html auto_view text/html
alternative_order
prioritizes the plain text version of an email (if
it exists) over it’s html variant. If it doesn’t exist, it’ll display
the html version. However by default Mutt doesn’t automatically
display any non plain text email. You have to invoke that manually, or
just add the auto_view
setting.
That’s all well and good but what about all the fancy html and styling
that elinks just can’t render? There are going to be images and fancy
formatting that I might want to view. In that case I have to resort to
good old Firefox and put the following in my mailcap
.
text/html; firefox %s;
It’s important to put that entry above all other text/html
entires. That way Mutt will default to Firefox when manually
evoked. Now I can easily open up an email in a Firefox tab by pressing
v
to view the attachments and m
on the appropriate text/html
attachment I want to view in Firefox.
Persistent Mutt
Initially I would launch Mutt, let it retrieve any new emails and then
close Mutt when I was done with it. As time went on I found I just
kept Mutt open in a terminal constantly. Unfortunately Mutt doesn’t
automatically retireve emails by default. You have to manually sync
with the server using $
. This is easily remedied by adding a simple
setting to my muttrc
.
set imap_check_subscribed
By default, Gmail will have a list of folders. These are all defined
in the Labels tab of Gmail’s settings. There’s a handful of default
ones (some we’ve already seen like Trash, Sent, and INBOX) and any
custom ones we can define. The imap_check_subscribed
setting adds all
these to the mailboxes
list which are then automatically polled for
new mail. I want to query everything for new mail but if I wanted to
query only specific folders I could get rid of the
imap_check_subscribed
setting and add the individual folders to the
mailboxes
list like this:
mailboxes +INBOX +friends +work
There is a setting called mailcheck
that determines how often Mutt
checks the mailboxes
for new mail. The default is 5 seconds which in
my opinion is unnecessary for most people. I changed it to 120 seconds
(or 2 minutes) for my needs.
There are a few other settings that worthwhile to look into. timeout
,
imap_keepalive
, and imap_passive
.
Good to Go
At this point we have a configuration that I would consider acceptable for everyday use. Here’s what mine looked like exactly.
## IMAP set folder = "imaps://imap.gmail.com" set imap_user = "bassam.saeed@gmail.com" set imap_pass = `pass mail/gmail/mutt` set imap_check_subscribed unset imap_passive set mail_check = 120 ## SMTP set smtp_url = "smtps://bassam.saeed@gmail.com@smtp.gmail.com" set smtp_pass = `pass mail/gmail/mutt` set realname = "Bassam Saeed" set from = "bassam.saeed@gmail.com" set edit_headers = yes ## LOCATIONS set header_cache = "~/.mutt/cache/headers" set message_cachedir = "~/.mutt/cache/bodies" set mailcap_path = "~/.mutt/mailcap" ## FOLDERS set spoolfile = "+INBOX" set postponed = "+[Gmail]/Drafts" set trash = "+[Gmail]/Trash" ## UI alternative_order text/plain text/html auto_view text/html set sort = reverse-date-received
I am currently working on part two, hopefully it’ll be up soon.