...making Linux just a little more fun!

Mutt configuration

By Silas Brown

The Mutt email client is very useful, especially for dealing with large volumes of mail, but it might need careful configuration. This article explains a few points about configuring Mutt.

mutt's BCC problem

The first problem I'd like to address is the Mutt+Exim BCC privacy leak. By default, mutt relies on the MTA (mail transfer agent) to remove the BCC (blind carbon copy) headers from messages. Some MTAs such as Exim will not do this by default, or at least not the way Mutt calls them. Therefore, it is possible that your BCC headers will be visible to all parties. In some circumstances this could be a major privacy leak. Moreover, your Mutt might be configured to hide BCC headers on incoming mail, so if you think you're safe because you sent yourself a test message and didn't see its BCC header, think again! Check the full headers for BCC lines. Your correspondents on Yahoo and GMail et al will see them if they're there.

I know a university that actually removed Mutt from its Linux systems due to the potential seriousness of this problem, but there are several possible workarounds:

Solution 1: Don't write BCC headers at all

This is what most .muttrc writers seem to do and it's the easiest. Set write_bcc=no in your .muttrc and BCC headers will never be written to messages at all (but the blind carbon copies can still be sent).

The documentation for mutt's write_bcc option (which defaults to YES) is slightly confusing, because it says "Exim users may wish to use this". To me, "use this" means "leave it set to YES", but what they actually mean is "Exim users may wish to change this" i.e. set it to NO.

The problem with write_bcc=no is it will leave you with no record of who you have BCC'd in your messages. (When you browse your copyself or sent-mail folder, mutt will not by default show the BCC line anyway, but it will if you examine full headers by pressing h.)

Solution 2: Use Exim's -t option

By setting Mutt to use Exim's (or Sendmail's) -t option, you can tell Exim to take the delivery addresses from the message itself not the command line, and also to strip BCC headers. However, there are two problems to work around:

Firstly, Mutt's "Bounce" message command will no longer work: it will just resend the message to its original set of addresses. So I suggest disabling the b key to stop you from running the "bounce" command by accident:

bind index b noop
bind pager b noop

Secondly (and more importantly), when running Exim with the -t option, Exim defaults to interpreting the command-line addresses as addresses to remove. Since mutt puts all the delivery addresses on the command line, Exim will end up not delivering to any of them!

Most websites tell you to change your Exim configuration to get around this, but that requires root privileges which you might not have, and it may also break things if some of your users have other mail clients. But there is a way to get around the problem without changing the Exim configuration.

Basically, what we want to do is to stop mutt from putting the email addresses on the command line. There doesn't seem to be a way of telling mutt not to do that, so let's try to make sure that those command-line addresses don't get as far as Exim. That can easily be done by writing a shell script that calls Exim, and get Mutt to call our shell script (and our shell script can ignore the arguments that Mutt puts on its command line). However, it turns out that you don't even have to write a shell script; there's a way you can do it from within .muttrc itself.

What we want to achieve would be something like

WRONG: bash -c sendmail -t #

(I put WRONG: besides that in case anyone's skimming through the article and only looking at the examples.) What that's supposed to do is, get the bash shell to call sendmail -t, and add a # (comment) character so that any email addresses that mutt adds to the command line will be ignored.

The above command won't work though, because bash's -c option requires the entire command to be in one argument i.e. quoted; any other arguments go into its $0, $1 etc. But it's no good quoting the command in .muttrc because mutt's code wouldn't know how to interpret the quotes (if you say "sendmail -t" to pass the single argument sendmail -t, mutt will pass "sendmail as the first argument and -t" as the second argument which will not help).

However, bash does have a built-in variable $IFS which defaults to space. So if we write $IFS instead of space, we can make it work. We don't even need the comment character #, because only the first argument after the -c will be actually interpreted by bash (the others will go into $0 etc, which will be ignored by the command we're going to give). The only thing we need to be careful of is to make sure that mutt does not try to expand the $IFS itself ($IFS is a "special" variable, not usually a real environment variable, so if mutt tries to expand it then it will likely end up with nothing). To stop mutt from trying to expand the $IFS, we must use single quotes ' rather than double quotes " when setting the variable:

set sendmail='/bin/bash -c $1$IFS$2$IFS$3$IFS$4 bash /usr/sbin/sendmail -oem -oi -t'

(The -oem and -oi options are what Mutt uses by default.)

Solution 3: Use a helper MTA

BCC headers are always removed by Exim when a message is submitted via SMTP. Mutt cannot submit messages via SMTP itself, but you can use a small MTA like msmtp to do so, and get Mutt to run msmtp. This can be done even if you don't have root privileges on the system; just compile msmtp in your home directory if necessary, and configure it to send all messages to the real MTA via SMTP.

set sendmail=$HOME/msmtp/bin/msmtp

This method has the advantage that everything works: BCC information is still stored in sent-mail, the Bounce command still works, and BCC is removed from outgoing mails. Additionally, it does not require root privileges or Exim configuration. The only problem is it requires the additional setup of msmtp rather than being a self-contained solution within .muttrc.


After setting things up, I highly recommend you test that BCC headers have indeed been removed. Try sending yourself an email and BCC'ing another address (which doesn't have to exist; just ignore the delivery failure), and then inspect the headers of your email when it is delivered to your inbox. Remember though that Mutt might not be showing BCC headers on incoming email anyway, so press h to view the full headers.

If you want Mutt to show BCC headers on incoming messages (and in your own sent-mail), put this in your .muttrc:

unignore bcc

And you can optionally change the order of headers as well:

unhdr_order *
hdr_order From Date: From: To: Cc: Bcc: Subject:

but mentioning Bcc: in hdr_order is not sufficient; you need the above unignore directive as well.

Disabling unconfirmed quit

A second "gotcha" of Mutt is the "unconfirmed quit" key, Q (that's a capital Q). I like to automatically delete messages marked for deletion when leaving a folder (the alternative is to lose the deletion marks, so might as well):

set delete = "yes";

but with this setting, pressing Q by mistake will act as an unconfirmed delete-messages-and-quit. The problem? A lower case q is used to quit out of individual-message view and go back to folder view, and the "undelete" key is by default available only from folder view. So if you accidentally hit D to delete a message, then want to undelete it, but you are in message view and need to first go back to folder view before you can use the undelete command, so you press q to go back to folder view, then what happens if you left Caps Lock on by mistake? Goodbye, messages! (Leaving Caps Lock on by mistake is not so easy from a desktop, but it's surprisingly easy from a PDA or phone with an SSH client on it.) Therefore I recommend disabling the capital Q keypress:

bind index Q noop
bind pager Q noop

Making search more useful

A Mutt "simple search" (as opposed to a full-text search which takes longer) defaults to looking in the From and Subject fields. It's more useful if it also looks in the To field, so you can use your sent-mail folder like an extra address book:

set simple_search = "~f %s | ~t %s | ~s %s";

Viewing complex messages

mutt can be set to automatically display HTML etc using mailcap filters if possible:

set implicit_autoview = 'yes';

but more generally, sometimes you get a message that warrants viewing in a Web browser (for example it might be written in a language that your terminal doesn't display). Mutt can be made to do this in several ways. Since I never print email from Mutt, I set the Mutt "print" command to be a "send this message to a Web browser" command, using the program mhonarc to format the message for the browser:

set print = 'yes';
set print_decode = 'no';
set print_split = 'no';
set wait_key = 'yes';
set print_command="cd $(mktemp -d ~/public_html/mailXXX);sed -e $'s/\\f/From \\\\n/'|LANG=C mhonarc -;[ a\$WEB == a ]&&export WEB=$(hostname -f);echo;echo http://\$WEB/~$(whoami)/$(pwd|sed -e 's-.*/--')/maillist.html;echo Then rm -r $(pwd)";

Note that the above print_command cannot be made much longer, because some versions of mutt will truncate it. That truncation happens after expansion of environment variables, which is why I escaped some of those $ characters. If you need to do more, then make a separate script and call that.

The above command allows you to set the WEB environment variable to the webserver's name if it's different from your hostname. This is useful in some setups if your home directory is mounted over NFS and the Web server is on another machine.

If your MHonarc mangles UTF-8 messages, you might have to set the environment variable M2H_RCFILE to a file containing the contents of http://www.mhonarc.org/MHonArc/doc/rcfileexs/utf-8-encode.mrc.html

Message sort order

It seems that different versions of Mutt default to different sort orders, but you can set it in your .muttrc. I usually use reverse date:

set sort=reverse-date-sent;

Using maildir

Mutt is one of the few mail clients that supports the maildir format. I highly recommend the maildir format, which puts each message in a separate file on the disk.

set mbox_type = 'maildir' ;

Having each message in a separate file means not so much disk activity when changing just one message (i.e. it's faster, and if you're using a flash disk then it's also less wear on the disk). It's also easier to archive old messages etc just by using shell utilities; there's more than one way to do this but I usually use the archivemail program. Furthermore there are many scripts available on the Web which will write new messages to a maildir folder; you can adapt one of these to your mail filtering system and have it add messages to all your folders in the background even while Mutt is accessing them for search etc. (I used Yusuke Shinyama's public-domain pyfetchmail.py and adapted it to fetch IMAP instead of POP by using Python's imaplib module.)

Other configuration options

You should probably look through Section 6 of the Mutt manual (and perhaps chapter 3 as well), to check if there are any other options you'd like to set.


Talkback: Discuss this article with The Answer Gang

[BIO] Silas Brown is a legally blind computer scientist based in Cambridge UK. He has been using heavily-customised versions of Debian Linux since 1999.

Copyright © 2011, Silas Brown. Released under the Open Publication License unless otherwise noted in the body of the article. Linux Gazette is not produced, sponsored, or endorsed by its prior host, SSC, Inc.

Published in Issue 182 of Linux Gazette, January 2011