Hack and / - Mutt and Virtual Folders

 in
Why limit yourself to searching for messages within one folder in mutt? You are a few short shell scripts away from multifolder searching bliss.

If you didn't already know, I'm a mutt-addict^H^H^H^H^Huser. At this point, I can't even remember when I started using mutt. All I do know is that every time I try another mail client, I just get frustrated by how long it takes to go through my e-mail. Well, that, plus try to navigate a GUI e-mail program with vi key bindings—it (usually) doesn't work.

Why try other mail clients if I love mutt so much? Well for one, some of the other mail clients do have a few interesting features, such as virtual folders. With a virtual folder, you can create a keyword search, and then all messages that match the search end up in a special folder you can browse. Well, it turns out, the same functionality is available in mutt if you use maildirs and are willing to do a little scripting.

One major problem with the default search abilities in mutt is that you can search within only one folder at a time. I store just about everything that's important in e-mail, and I have many different folders with even more procmail rules to sort incoming mail between them. The downside to this is occasionally I can't remember exactly in which folder a particular e-mail message is located.

The solution to the mutt search problem takes advantage of the fact that if you use maildirs on your mail server, each folder is a directory on the server, and each e-mail message is a file within that directory. Basically, a script can go through each of your folders and grep for your keyword and then create a new maildir with symlinks to any matching files. I named my solution maildirsearch, and it looks something like this:

#!/bin/sh

MAILDIRS="$HOME/mail"
VFOLDER="search"
VFOLDERPATH="$MAILDIRS/$VFOLDER/cur/"
FOLDERS=`ls $MAILDIRS | egrep -v "search|flagged"`

rm -f $VFOLDERPATH/*

for i in $FOLDERS
do 
   for j in `egrep -lR "$@"  $MAILDIRS/$i`
   do
      ln -s $j $VFOLDERPATH/;
   done;
done;

Next, I created another script called muttsearch that would execute my maildirsearch script, then open a new instance of mutt that reads the new virtual search folder. One nice feature of using this method is that I can see the search results grow within the mutt window and start reviewing results immediately:


#!/bin/sh

VFOLDER="search"
$HOME/bin/maildirsearch "$@" &
sleep 1;
mutt -f "=$VFOLDER" && killall maildirsearch >/dev/null 2>&1

Finally, I set up a key binding in mutt so that I could press Esc-S, type in a keyword (or regex) and start the search:


macro index \eS "<shell-escape>$HOME/bin/muttsearch \""
macro browser \eS "<shell-escape>$HOME/bin/muttsearch \""

Now, there is a downside to this script—it's designed to be run on the server that stores the messages. In my case, I use a tool called offlineimap to sync my remote e-mail server with my laptop, so I always have a copy of my messages locally. If you don't want to go that route, but want to be able to search from your local machine, you potentially could modify my muttsearch script so that it SSHes into your mail server and executes the script.

The script actually works well for me, but I realized after some time that I did a lot of the same searches over and over again. For instance, I am a heavy user of the “flag for follow-up” function in mutt. If you are in the message index and press the F key, it sets a flag on the message and displays an exclamation point in front of it. I use this to remind myself that I need to reply to a message. The downside to this is that I have to go to a particular folder regularly to see the flag, and sometimes I want to see all of my flagged messages at once. It turns out that the same virtual folder concept I used for my search works well for this too.

First, I created a script called flag-folder. When you flag an e-mail in a maildir system, the e-mail gets an F added after the last comma in the filename. Basically, my flag-folder script searches through all my maildirs for files that match the pattern and then symlinks those files into a new maildir named flagged:

#!/bin/sh

# This script finds all the flagged e-mail in a 
# Maildir and symlinks them to a 'flagged' folder 
# in the Maildir. 
# To run it every 5 minutes, for instance, add the 
# following to the user's crontab:
#
#       */5 *    * * *   /home/greenfly/bin/flag-folder

MAILDIR="$HOME/mail/"      # path to your maildir
FLAGGED="${MAILDIR}/flagged/cur" # path to your 
                                 # (precreated) flagged folder

cd $FLAGGED
rm ${FLAGGED}/*

# find all the files in the maildir, then search for 
# flagged files (files with an F after the last comma 
# in the filename) and symlink them
find ${MAILDIR} -type f | perl -ne '$foo = ""; $foo = 
 ↪(split ",", $_)[-1] if(/,/); if($foo =~ /F/){chomp; 
 ↪system "ln -s $_ .\n";}'

As you can see in the comments in the script, you also simply can set this up as a cron job on your mail server so that your flagged folder is updated constantly. Then, I created a script similar to my muttsearch script called muttflag that basically does the same functions, except for the flag-folder script:


#!/bin/sh

VFOLDER="flagged"
$HOME/bin/flag-folder &
sleep 1;
mutt -f "=$VFOLDER";

Finally, I created another key binding so that pressing Esc-F executes the muttflag script:


macro index \eF "<shell-escape>$HOME/bin/muttflag \n"
macro browser \eF "<shell-escape>$HOME/bin/muttflag \n"

There are a lot of other possibilities when you use virtual folders in mutt. So far, the only big downside I have found is that because the script uses symlinks, any flags applied to messages within virtual folders don't apply to the real message. For instance, if you reply to a message within a virtual folder, it updates the filename for the symlink, but not the file it links to. Essentially, this means you lose that reply flag unless you go to the original folder and reply.

Apart from the downsides though, I'm pretty happy with virtual folders in mutt. Once again, it's faster than searches I've seen in other clients, plus I get to keep my vi key bindings, which you can have when you pry them from my cold, dead IBM Model M keyboard.

Kyle Rankin is a Senior Systems Administrator in the San Francisco Bay Area and the author of a number of books, including Knoppix Hacks and Ubuntu Hacks for O'Reilly Media. He is currently the president of the North Bay Linux Users' Group.

______________________

Kyle Rankin is a systems architect; and the author of DevOps Troubleshooting, The Official Ubuntu Server Book, Knoppix Hacks, Knoppix Pocket Reference, Linux Multimedia Hacks, and Ubuntu Hacks.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Try mairix

Anonymous's picture

mairix does indexing to make searches even faster. It also works by creating symlinks, so it will have the same model as your script.
http://www.rpcurnow.force9.co.uk/mairix/

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState