My mail client of choice is Mutt. It works. It works well. It works
well over SSH, and will do just about anything I ask it to, as long as
what I ask it to do is to manage my mail. Plus, it’s fast.
I also have been using David Allen’s system known as Getting Things
Done, or GTD. Tonight I did a little Mutt configuration to automate
some of the GTD-style email reading I’ve been doing.
The principle is to have every incoming mailbox completely empty by the
time I’m done reading it. The messages get deleted or sorted into other
boxes where they either wait for more information or generate actions
for me to do when the time is right.
A little googling revealed that others have done something similar in
recent years, but there were two problems. First, messages were tagged
by adding an “X-Label:” header, which supposedly required a patch to
Mutt’s source code. Possible, but a bit ugly. I vastly prefer custom
configuration to custom software, when possible. Second, a number of
the pages about using Mutt in a GTD way are no longer available.
But this one is available. Unfortunately, it also
relies upon the “Add an X-Label header” patch to Mutt’s source code.
But I had an inkling it could be done another way, without the patch. A
few hours later, after a little Reading of The Fine Manual and some
experimentation, I have the answer.
The goal is to provide simple keystrokes that will add an X-Label header
or change an existing one right from the index listing or the pager.
Then, folder hooks can change the index listing format when needed to
include the X-Label header — or at least a few characters of it. That
way, I can process messages when they come in, slap a label on them, and
then save them into an appropriate folders for later review at the right
time. When I browse those folders later, I’ll see my labels, and know
what to do even before I read the messages. In addition, I can set up
automated summaries of my GTD folders, including how many messages are
there, and what their Labels say. The summaries might appear on my
desktop, or wherever else I might want them.
I ended up doing most of what’s mentioned on the page linked above. The
chief difference is that I haven’t patched Mutt. So instead of using
the “edit-label” command (which doesn’t exist for me), I used the
following somewhat long binding (inspired by this thread) in
my muttrc:
macro index,pager Cl "<enter-command>set my_editor=$editor<enter>\
<enter-command>set editor='~/bin/mutt-setlabel.sh'<enter>\
<edit><enter-command>set editor=\$my_editor<enter>"
The magic keystroke is Cl, available in the index or the pager.
Everything else is the macro this keystroke performs.
First, we save the value of the current Mutt editor variable to a custom
variable, cryptically named my_editor.
Then, we set the Mutt editor to a shell script, which I’ll include below.
After that, we issue the Mutt command, which edits the current
message, using the script we specified a moment ago.
Finally, we restore the original value of the Mutt editor variable. The backslash
is needed here because we want this variable to be expanded when the macro
executes, rather than when it is defined.
The shell script is as follows:
#!/bin/bash
read -e -p"Enter an X-Label: " value
file=$1
formail -I "X-Label: $value" <$file >$file.tmp
sleep 1
mv $file.tmp $file
Ignore the first line. It’s how shell scripts work.
First, on line 2, we have Bash ask for a new label value. Since Mutt
runs in a terminal, this is no problem at all.
The third line takes the filename parameter provided by Mutt and puts
it into a nice, descriptive variable, just because.
The fourth line uses a command-line utility to do the heavy lifting,
using the value we just obtained in line 2. Shell redirection is used
for input and output.
The fifth line pauses for a second, because supposedly Mutt will assume
the file is unchanged if the final timestamp is unchanged.
Finally, we move the modified message to the original filename for Mutt
to pick up.
And that’s it. The rest is similar to the first link above.
But now, it’s late. My next action is to get some rest.