About two weeks ago, I was singing the praises of mutt, patting myself on the back for improving my mail toolchain configuration, and complaining that GUI mail apps always make me feel stifled. I was asked to elaborate, so here goes.
My complaint is almost entirely that GUI MUA's are not very easily configurable, and not usually very configurable at all. The first place this bugs me is in the mail composer. I write plain text email messages. I use a very good tool for writing plain text, Vim. When I write plain text that happens to be an email message, I don't want to use a different tool -- especially since I will be less familiar with it, and since it will surely be less powerful than Vim.
There have been hackish extensions for Mozilla products to use external
programs for text editing, but they've always felt clunky, and have never
worked very well on OS X. Outlook has long offered the ability to use an
external program, but unfortunately that program is Word. To be fair, I don't
need most of the power of Vim when composing an email, but it's annoying to
forget that I've been forced into an inferior editor and end up with
in the middle of my message.
I don't know how much non-spam email I receive in a day. (Note to self: add
procmailrc.) It's at least a few hundred, I think, because of
the automated messages and mailing lists that I'm on. I use
procmail to sort
these into folders, and one of the ways I do that is by using a different
receiving address for most things. It's easier than looking for telltale
headers, because a single procmail rule can tell that, for example,
firstname.lastname@example.org goes to the
inbox/perl/bogus folder. Of
course, this means that when I send mail to that list, I want to send from that
address. With Mutt, I can just write a hook or two that change my sending
address based on the destination or the folder that I'm looking at when I start
composing. Even better, I can (and did) write a program with a list of the
lists that I'm on, and it can generate all the lines I need for my
including setting up mailing list recognition, hooks for automatically setting
the from header, and other special configuration.
In GUI MUA's, it much more of a pain to have multiple "from" addresses. Some require that they're tied specifically to an "account" object, which gloms in all sorts of other settings. Others (like Mail) just give you a drop-down menu of all your configured addresses, which is insane if you have, like I do, hundreds. Setting them automatically is basically a non-starter.
Most mail programs have a pretty limited definition of a mailbox. It's usually something like, "a mailbox is either a file on disk in a proprietary format or a set of messages accessed across IMAP or POP."
Mutt can read mailboxes stored in mbox, Maildir, and mh format. It can read
messages via POP or IMAP, and it can tunnel either of those across SSH.
Tunneling across ssh is a huge deal, because in combination with
it means that mutt can access remote mailstores with no interactive
authentication required, and without storing your password in Yet Another
Questionable Password Repository.
Sometimes, I've got a folder of mail that I want to browse just this once, for
whatever reason. In almost every GUI MUA that I've used, I would need to add
an account to my preferences, which would usually involve a bunch of menus,
clicking, and maybe a wizard or two. (In Outlook, I might not need to add it,
but I would need to be able to browse to it on an Exchange server, which is
just as tedious.) With Mutt, I can just use the
-f switch and give a file
or network location, and Mutt reads the folder.
Mutt's displays are hugely configurable. Every status bar can be rewritten,
as well as the format of every item listing, as far as I know. The color of
any bit of the display can be configured, including parts of the body. For
example, this line in my
muttrc does a good job at highlighting any email
addresses in the body:
color body brightgreen default [-0-9A-Za-z.]+@[-0-9A-Za-z.]+
These lines say "messages are listed in grey, unless they're unread, in which case they're white, unless they're PGP signed, in which case they're green, and they're brighter green if they're unread":
color index white default ~A color index brightwhite default ~U color index green default (~g|~G) color index brightgreen default "(~g|~G) ~U"
At best, most GUI MUA's let you change a few colors and the columns shown in item listings. What's worse, you usually can't change the formatting of the columns, except by changing the global display of that type of datum. So, if I have some folders that are guaranteed to contain messages only from a given month, I can't say, "in this folder, display date as the two digit day of month."
Actually, these days most, if not all, of the major GUI MUA's support S/MIME or PGP/MIME, even if only through a plugin. Mutt's superiority comes from integration with hooks. I can say things like:
Saying that a CLI MUA is better than a GUI MUA because it uses the keyboard isn't begging the question. GUI MUA's also use the keyboard, but they tend to do so poorly. They provide convenient (usually) keystrokes for what the authors believe are the most popular features, but configuration beyond that tends to be very difficult, if it's possible at all. In Mutt, it's trivial to reconfigure every key. I have a bunch of bindings to make it more Vim-like. Here's a small sample:
bind index ^B previous-page bind index ^F next-page bind index gg first-entry bind index G last-entry bind index z<Enter> current-top bind index z<Return> current-top bind index zz current-middle bind index z- current-bottom
Here's a very slightly clever macro:
macro index ~ ":macro index ^] c=spam.\`date\ +%Y.%m\`\\r\r^]"
Hitting the tilde key in the index takes me to the current spam folder (where
my procmail is dumping spam), regenerating the name of the folder each time --
because if it was only defined when the
muttrc was loaded, it would become
inaccurate if the month changed during a
Mac OS X has a "location" setting, and I think Win32 has something similar. They let you have different profiles for various things based on whether you're at home, at work, or so on. Unfortunately, every single program does not tie into them, so it's not so easy to say, "If I'm running at work, connect to the really fast internal IP, but otherwise use the VPN."
I wrote a little script called
which-config, which I use like this:
which-config decides what file to include in
muttrc based on things like
the MAC address of the hardware it's running on, the current IP address, and so
on. I could easily extend it to check OS X location, time of day, or whether
I'm running under sudo. At present, it's fifteen lines long, counting the
shebang, strictures, and warnings.
Since it's a console program, Mutt can't (practically) display HTML, images,
or video inline. That's okay, because I am not usually that interested. It
does something really useful instead: it consults the
mailcap file to figure
out how to handle attachments. So, if I receive a
message, Mutt will first try to display the text part. If there is none, it
will use the HTML part, and it will use
lynx to convert the HTML to
plain text for display in the window. I can tell it that images should be
opened by Preview or gqview -- based, of course, on what
which-config has to
say. If I was really twisted, I could have images converted to ASCII by aalib
and then displayed inline. I am not, yet, that twisted.
At work, we have a number of special attachment types for automated requests that get personally approved. With the proper global configuration, non-technical staff members can easily tell Mutt to approve the request.
Like many MUA's, Mutt lets you select a bunch of messages and then perform some operation on them. You can do this by tagging each message (which is sort of like command- or control-clicking each one to add it to the selection) and then giving a command like "for this batch, do X." If you want to operate on all messages with given qualities, though, you can use patterns. Patterns can check all sorts of things: whether a message is deleted, whether a message is PGP signed, whether a message was sent in a given absolute or relative time range, whether its body or header contains certain text, whether the message was sent to you or by you (or to or by anyone else), and all sorts of other things. Naturally, they can be combined with simple logical operators.
These patterns show up all over the place: in hook definitions, in batch operations (do X to all messages matching Y), and in display limits (only show messages matching Y). Some GUI MUA's have tolerable search features, but they often end up returning a second-class folder-like result set on which a only a subset of normal operations are available. (They usually operate across all folders, though, which is not easy to do in Mutt.) I have not yet seen a way to tell a GUI MUA to select all messages matching given criteria, which is not to say that it isn't possible.
What bothers me more about searching in GUI MUA's is that it's so labor-intensive. There's usually a special "search criteria" dialog box, generally with some kind of expanding grid interface, and if boolean logic is available at all, it's usually awkward and limited.
Apple Mail's ability to save searches as virtual mailboxes is a fantastic feature, and one that I've wanted in my MUA for years. Someday, I hope to see it integrated into an IMAP server so I can stop pining for it.
While I praised the ease with which one can create multiple profiles, there's a
drawback to my method: it occurs at
mutt's initialization, so it's difficult
to switch back and forth between profiles during one session, which would be
useful for using one
mutt for reading work and home email. If each
configuration somehow "reset" all existing configuration and then reloaded the
correct profile, a macro could be made to do this... and in fact, now that I
write this down, I believe it's possible. The macro would do something like:
reset all unhook all source muttrc
The difficult will be in fixing bindings (if any must be changed, which is
actually unlikely, for me) and in changing what
which-config will return.
Another failing in Mutt (in my opinion) is that its regex are non-capturing. (If one of the worst things I can say about my MUA is that "its regex are non-capturing" than either I'm a lousy critic or it's a fantastic MUA. Please let me know if I am a lousy critic.)
With capturing regex, it would be easy to write something like this:
folder-hook =list.(.+) my_hdr From: <email@example.com>
Instead, I need to generate all the needed hooks one by one, since the action taken on the right hand side of the hook is constant.
Mutt has a very primitive format for storing address book entries (called
aliases). They're alright for simple use, but it's hardly suitable as a way to
store a real address book. To make it easier to use an external address book,
Mutt provides the
query_command setting, which lets you specify an external
program for finding addresses. It isn't very well documented, but it's simple.
The bigger problem is that it's one-way. Mutt supports adding new aliases to a
file -- that is, if you hit a key, it will set up an alias for the sender of
the message you're reading. It doesn't support a way to send alias information
to an external program.
I suppose the solution there is to wrap
mutt in something that checks for the
output file on quit and imports things... but that seems pretty ugly.
I am sure there are annoying things about Mutt that I've missed. (I was
surprised while writing this, though, to find that one or two of my pet peeves
have been addressed in the last year or two. e.g., there is now a
imap_check_subscribed option.) I'm also sure there are things you can do
with a GUI MUA that aren't possible with Mutt.
I am interested to hear about both of these things. Everybody knows that I'm pretty interested in email, and that includes MUA's. Why should I use anything other than Mutt? (That said, I know why my parents should use something other than Mutt.)