Search

Cleaning Your Inbox with Mutt

Teach Mutt yet another trick: how to filter messages in your Inbox
with a simple macro.

I'm a longtime Mutt user and have written about it a number of times in
Linux Journal. Although many people may think it's strange to be
using a
command-line-based email client in 2018, I find a keyboard-driven email
client so much more efficient than clicking around in a web browser. Mutt is
extremely customizable, which presents a steep learning curve
at first, but now that I'm a few decades in, my Mutt configuration is pretty
ideal and fits me like a tailored suit.

Of course, as with any powerful and configurable tool, every now and then I
learn of a new Mutt feature that improves my quality of life dramatically. In
this case, I was using an email system that didn't offer server-side filters.
Because I was a member of many different email groups and aliases, this meant
that my Inbox was flooded with emails of all kinds, and it became difficult to
filter through all the unimportant email I wanted to archive with the emails
that demanded my immediate attention.

There are many ways to solve this problem, some of which involve tools
like offlineimap combined with filtering tools. With email clients like
Thunderbird, you also can set up filters that automatically move email to
other folders every time you sync. I wanted a similar system with Mutt,
except I
didn't want it to happen automatically. I wanted to be able to press a key first so I
could confirm what was moving. In the process of figuring this out, I discovered a few gotchas I
think other Mutt users will want to know about if they set up a similar
system.

Tagging Emails

The traditional first step when setting up a keyboard macro to move email
messages
based on a pattern would be to use Mutt's tagging-by-pattern feature (by
default, the T key) to tag all the messages in a folder that match a certain
pattern. For instance, if all of your cron emails have "Cron Daemon" in the
subject line, you would type the following key sequence to tag all of those
messages:

TCron Daemon<enter>

That's the uppercase T, followed by the pattern I want to match in the
subject line (Cron Daemon) and then the Enter key. If I type that while I'm
in my Mutt index window that shows me all the emails in my Inbox, it will tag
all of the messages that match that pattern, but it won't do anything with them
yet. To act on all of those messages, I press the ; key (by default), followed by
the action I want to perform. So to save all of the tagged email to my
"cron" folder, I would type:

;s=cron<enter>

That's ; followed by the s key to save, followed by the name of the folder
to save to, where =cron means "the folder named cron that sits under the
Inbox". To combine all of this into a macro so I can trigger this action
by pressing, say, .c, I would add the following to my Mutt configuration file:

macro index .c "TCron Daemon<enter>;s=cron<enter>"

Or, if you want to make it more portable (in case you remapped your save
command to another key), you could do this:

Of course, if you're cleaning out a lot of messages in your Inbox, you'll
probably have a lot of different patterns to match. For instance, I want
to move all of the DMARC report messages that are sent to the dmarc-reports
email address, so I'm going to add another pattern to this macro that will save all
of those messages to my dmarc folder. By itself, the macro would look like
this:

The most important difference here is that for my tagging pattern, instead of
just matching on dmarc-reports, which would match only the subject line, I
typed ~C in front of it, which tags all messages that have "dmarc-reports" in
the To: or CC: headers. The combined macro just combines the two lists of
keypresses one after the other and looks like this:

The Problem

The above macro has a subtle problem though, and unless you have set up a
Mutt macro like this in the past, you may not notice it. In fact, the first
couple times you run the macro, it may seem like it works—as long as there
are matching messages in your Inbox. The problem occurs if you don't have any
matching messages. The way that Mutt interprets this macro, if you don't have
any matching messages, it still will happily apply any commands that follow
the <tag-prefix> command—only to whatever message the cursor is currently
under! Luckily I was just moving messages around, but if you told Mutt to
delete tagged messages, they would be gone for good!

The solution here is to use a special Mutt command called
<tag-prefix-cond>
instead of <tag-prefix>. This tells Mutt to execute the command
following <tag-prefix-cond> only if Mutt actually has any messages tagged. You
then wrap the command with <end-cond> to tell Mutt that conditional command
is completed. So for a simple macro, I would replace:

Now when I want to add a new filter for my Inbox, I can test the tag command
one time within Mutt by hand to confirm it does what I expect, and then
append it to my macro. Now when I load my Inbox, I can press a simple key and
perform those filters. If you want this to be automatic, you would
just set up a folder-hook statement for your Inbox folder that uses the Mutt
push command to press all of the keys in the above macro.

Kyle Rankin is a Tech Editor and columnist at Linux Journal and the Chief Security Officer at Purism. He is the author of Linux Hardening in Hostile Networks, DevOps Troubleshooting, The Official Ubuntu Server Book, Knoppix Hacks, Knoppix Pocket Reference, Linux Multimedia
Hacks and Ubuntu Hacks, and also a contributor to a number of other O'Reilly books. Rankin speaks frequently on security and open-source software including at
BsidesLV, O'Reilly Security Conference, OSCON, SCALE, CactusCon, Linux World Expo and Penguicon. You can follow him at @kylerankin.