The Mutt e-mail client

Mutt
All mail clients suck. This one just sucks less. — Michael R. Elkins

Mutt is a text-based e-mail client for UN*X systems. It doesn't do nicely formatted HTML emails or images, but it's extremely customizable and completely keyboard-driven.

I have been using Mozilla's Thunderbird for a while now and I'm not completely satisfied with the way it handles mailboxes. It's time to try something 'new': Mutt. The plan is to use Mutt for all things e-mail for a full month.

A word of warning: Mutt is known for its complicated setup (there are literally hundreds of configuration commands), and I had to stitch together quite a few blog posts before I got a working setup. If you don't like braking and rebuilding stuff or hunting down a missing comma for half an hour, Mutt is probably not for you.

Fetching emails with isync

I use isync to synchronize my e-mail locally and Mutt to read and send emails. IMAP only. Mutt can do more, much more, but you will have to look elsewhere for that.

Mutt comes with IMAP support built-in. This works superbly but is a bit slower when dealing with larger mailboxes. Mutt's built-in IMAP support fetches your e-mail as soon as you start the program. There is a cache that is quite fast but requires a bit of patience every time you open the program. It also means you can't read your e-mail offline. I want a little more and use isync to download or better, synchronise, my e-mail locally via a crontab.

isync syncs your different e-mail accounts to a local folder structure. As much as it can be used outside of Mutt, they work together nicely and it makes Mutt faster and available on the go.

Be careful because isync doesn't download but synchronizes your mailbox! If you mess up the configuration, you could easily delete all your mail from the mail server. Play with a test account first and/or make sure you have a backup before you try this. You do have a backup, right?

The executable isync is called 'mbsync' and can be configured with a '.mbsyncrc' configuration file in your home dir. Let's configure our different IMAP accounts and add a crontab to fetch our new e-mail.

Create a '~/.mbsyncrc' file with the following:

  SyncState *
  Create Both

  # john@example.com

  IMAPAccount john-account
      Host       imap.example.com
      User       john@example.com
      Pass       secret_password
      UseIMAPS   yes
      RequireSSL yes

  IMAPStore john-remote
      Account john-account

  MaildirStore john-local
      Path  ~/.mail/john/
      Inbox ~/.mail/john/INBOX

  Channel john-inbox
      Master ":john-remote:INBOX"
      Slave  ":john-local:INBOX"

  Channel john-sent
      Master ":john-remote:Sent"
      Slave  ":john-local:sent"

  Group john
      Channel john-inbox
      Channel john-sent
  

Repeat this for every account you wish to synchronize. The example will only synchronize your inbox and sent mailbox, add other folders you might need, like a trash or spam folder. I had to create each of the account directories in '~/.mail' manually as well.

Now add a crontab command to fetch all e-mail every 5 minutes:

  */5 * * * * mbsync -a
  

The 'mbsync -a' command fetches all configured e-mail accounts. You can define different schedules with 'mbsync john', for example, which only synchronizes the john@example.com account in our configuration example.

Once done, you will see a folder for each channel in the ~/.mail/john directory with all your emails. You now have an offline copy, which is great.

Installing Mutt

Mutt time! Mutt doesn't come with a sidebar folder view out-of-the-box, but you probably want one. There is a patch, but you need to instruct Homebrew to include it when installing Mutt.

  brew edit mutt
  

to modify the Homebrew formula and add

  option "with-sidebar-patch", "Apply sidebar patch"
  

at the bottom of the block with all the options and add

  patch do
    url "https://raw.github.com/nedos/mutt-sidebar-patch/7ba0d8db829fe54c4940a7471ac2ebc2283ecb15/mutt-sidebar.patch"
    sha1 "1e151d4ff3ce83d635cf794acf0c781e1b748ff1"
  end if build.with? "sidebar-patch"
  

at the end of the section with all the patches.

And, finally, install Mutt:

  brew install mutt --with-sidebar-patch
  

Configuring Mutt

Muttt's config lives in the '.muttrc' file in your home dir, right next to the isync config file. However, I prefer a '.mutt' folder with a 'muttrc' (no dot here) file to have all the Mutt dependencies in a single place.

Let's start by telling Mutt where to look. Add the following to the '~/.mutt/muttrc' file:

  set folder           = ~/.mail            # mailboxes
  set alias_file       = ~/.mutt/alias
  set header_cache     = ~/.mutt/cache/headers
  set message_cachedir = ~/.mutt/cache/bodies
  set certificate_file = ~/.mutt/certificates
  set mailcap_path     = ~/.mutt/mailcap    # filetypes
  set tmpdir           = ~/.mutt/temp
  

and set some nicer defaults:

  set   wait_key   = no      # shut up, mutt
  set   mbox_type  = Maildir # mailbox type
  set   timeout    = 3       # idle time before scanning
  set   mail_check = 0       # minimum time between scans
  set   markers    = no      # no + sign for wrapped lines
  unset move                 # gmail does that
  set   delete               # don't ask, just do
  unset confirmappend        # don't ask, just do
  set   quit                 # don't ask, just do
  unset mark_old             # read/new is good enough
  set   beep_new             # bell on new emails
  set   pipe_decode          # strip headers and eval
  set   thorough_search      # also when searching
  color status cyan default  # while instead of black
  bind index gg first-entry  # cursor to first a la vim
  bind index G  last-entry   # cursor to last a la vim
  

Moving on to the sidebar. The following configures the up and down arrows to select a mailbox in the sidebar and the right arrow to open the selected mailbox. It also highlights the mailboxes with new emails.

  set sidebar_delim   = "  │"
  set sidebar_visible = yes
  set sidebar_width   = 20
  macro index,pager <up> "<sidebar-prev>" "previous folder in sidebar"
  macro index,pager <down> "<sidebar-next>" "next folder in sidebar"
  macro index,pager <right> "<sidebar-open>" "open folder in sidebar"
  color sidebar_new color221 color233
  set status_chars  = " *%A"
  set status_format = "───────────────────[%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]───%>─%?p?( %p postponed )?───"
  

Accounts

Let's configure an account. I created a file for each account and used the folder hooks to trigger the right config for the selected mailbox:

  folder-hook example/* source ~/.mutt/accounts/example
  folder-hook gmail/*   source ~/.mutt/accounts/gmail
  

And the 'example' file in the accounts folder:

  set realname            = "John Doe"
  set from                = john@example.com
  set use_from            = yes
  set my_smtp_user        = john@example.com
  set smtp_pass           = password
  set smtp_url            = smtps://$my_smtp_user:$smtp_pass@smtp.example.com
  set ssl_force_tls       = yes
  set smtp_authenticators = login

  set spoolfile = +example/INBOX # inbox
  set record    = +example/sent  # sent folder

  mailboxes Example \ # fake mailbox as divider
            +example/INBOX \
            +example/sent
  

Note that the password is not encrypted here. Therefore, only use this if you know what you are doing and make sure the file is only readable for your user. There are some ways around this if this scares you, but that's beyond the scope of this post.

If your password contains special characters ($, &, %, #, * and the like), you'll need to URL encode them. This took me a while to figure out. The password will be used in the 'smtp_url' setting so it makes sense you URL encode the special characters like you would in any URL. I used irb to quickly encode my password:

  require "uri"
  URI::encode("password")
  

The mailboxes section at the end of the file sets the mailboxes you will see in the sidebar. These have to match the mailboxes you defined earlier in the 'mbsync' configuration file. The first "Example" line is not a real mailbox, but a little hack to have a visual separation between the accounts.

You'll find plenty of Gmail example files if you want to add one of those. They are basically the same as the example above, but with Google's SMTP server and your Gmail address.

Quick Look

By default, Mutt saves attachments you open within Mutt to disk. This works but is cumbersome if you simply want to look at a photo someone sent you or quickly scan an attached MS Word document. OS X has this awesome Quick Look feature that quickly opens most files without having to install separate applications. Why not use Quick Look for e-mail attachments in Mutt?

Did you know you can run Quick Look from the command line with 'qlmanage -p file'? We''ll use this trick to tell Mutt to run Quick Look when opening attachments. Add a 'mailcap' file in the '~/.mutt' folder you created earlier with the following:

  text/html; qlmanage -p %s; nametemplate=%s.html
  text/html; lynx -dump %s; nametemplate=%s.html; copiousoutput
  application/pdf; qlmanage -p %s; nametemplate=%s.pdf
  image/jpg; qlmanage -p %s; nametemplate=%s.jpg
  image/jpeg; qlmanage -p %s; nametemplate=%s.jpg
  image/pjpeg; qlmanage -p %s; nametemplate=%s.jpg
  image/png; qlmanage -p %s; nametemplate=%s.png
  image/gif; qlmanage -p %s; nametemplate=%s.gif
  text/*; open %s
  application/*; open %s
  

Run Mutt; search for an e-mail with an attachment; press enter with the attachment selected and voila, quick previews without saving.

Sources

I obviously didn't find this all by myself so here are some of the most useful snippets I stole:

This post is open source. Did you spot a mistake? Ideas for improvements? Contribute to this post via Github. Thank you!