Colorizing messages in mutt (stab 2)

mutt-score-colors-example-scaledThis image shows the different scores (“[1000]” scores red background, “[800]” magenta text, etc.). At work I use a slightly different set.

I think I got it, at least in the index (for some reason it doesn’t work from the pager, maybe it’s the source command there)! I’m able to tag a message with a score, and have that score translate into a different color. Here’s the relevant part of my .muttrc:

# Star scoring 
source ~/.mutt/stars
bind index,pager s noop # I use 'y' to archive messages, no need for 's' to be bound to <save-message>.  This frees it up so I can use it below.

set my_red_star = 1000
set my_magenta_question = 800
set my_yellow_bang = 600
set my_green_star = 400
set my_green_check = 200
set my_blue_info = 100
set my_del_star = 0

macro index,pager sr "<pipe-entry>~/bin/stars $my_red_star<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with RED"
macro index,pager sm "<pipe-entry>~/bin/stars $my_magenta_question<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with MAGENTA"
macro index,pager sy "<pipe-entry>~/bin/stars $my_yellow_bang<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with YELLOW"
macro index,pager sc "<pipe-entry>~/bin/stars $my_green_check<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with GREEN"
macro index,pager si "<pipe-entry>~/bin/stars $my_blue_info<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with BLUE"
macro index,pager sg "<pipe-entry>~/bin/stars $my_green_check<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with GREEN"
macro index,pager sd "<pipe-entry>~/bin/stars $my_del_star<enter><pipe-entry>~/bin/del_stars<enter><enter-command>source ~/.muttrc<enter><sync-mailbox>" "Remove color marking from the current message"

color index default brightred '~n 1000-1100'  # Mark the message with red!
color index magenta default '~n 800-999'  # Mark the message with magenta!
color index black brightyellow '~n 600-799'  # Mark the message with yellow!
color index default green '~n 400-599'  # Mark the message with green!
color index green default '~n 200-399'  # Mark the message with green (check)!
color index brightblue default '~n 100-199'  # Mark the message with blue!

Not much different than I had before. The problems I had were the .mutt/stars, bin/stars, bin/del_stars. It mostly worked once I got it set up, except for messages that had special regular-expression reserved characters in the message ID. Here’s the bin/stars file I have:

#!/bin/bash
SCORE=$1                                
msgid=$(sed '/^Message-I[Dd]:[[:space:]]*/!d; s///; s/[<>]//g; s/[][$|]/\\&/g; q')
echo "score \"~i '$msgid'\" $SCORE" >> ~/.mutt/stars 

The key was the single quotes around the actual message ID. And the del_stars file:

#!/bin/bash

msgid=$(grep -m 1 '^Message-I[Dd]' | awk '{print $2}' | sed 's/[<>]//g; s/[^^]/[&]/g; s/\^/\\^/g')
sed -i "/$msgid/d" ~/.mutt/stars

After some further testing, it still doesn’t work. I have one company that sends me a bill summary, and the Message-Id has square-brackets around an RFC1918 address. Rather than fight with mutt trying to get it to read and score the message properly, I just added the company’s bill email address to my .mutt/stars file, with the following line:

score "~f CompanyEmail@company.com" 600

Also, to get the del_star script to work most times I have to close mutt completely before the score is removed. But otherwise it works!

Colorizing messages in mutt index

I’d heard a long time that if I’m a self-respecting Linux or UNIX geek I should use a terminal-based email client. My options are Alpine and mutt, and it seemed that while mutt was the hardest to get up and running, it was also the most flexible and powerful. I have drunk the Google Kool-Aid, so I had been loath to switch from Gmail, my workflow habits (in both personal and work Gmail) depending on certain features.

The first feature of Gmail (available in the “Labs” section) that I used very heavily was the multi-colored stars feature. At home, I use six different stars (green-check, yellow-bang, red-star, blue-info, purple-question, and green-star, in this order). At work I use eight (these and yellow-star, and blue-star). One thing I always hated about Gmail, is that I had to repeatedly click on the empty star icon in Gmail to cycle to the star I wanted. For seldom-used stars, this meant that I might not remember where it is in the list, so I’d accidentally cycle past it, sometimes multiple times until I got the star I wanted. Another problem with these stars is that they don’t translate to any other mail client. It would be really nice if Google would add something like “X-Gmail-red-star” or something to the email headers, but that isn’t what happens now (not sure if that would violate an RFC).

The other feature I use is the priority inbox, which separates the inbox into “Important and Unread,” “Starred,” and “Everything else.” I use this especially at work to help me triage email. I get a lot of stuff which isn’t junk, but that isn’t addressed (To: or Cc:) to me, so I don’t read it. All messages To or Cc’d to me get an automatic star (Gmail only has the capability to add yellow-star to messages automatically, something I hope to rectify with mutt. One day….).

The only thing I’ve figured out how to do in mutt thus far is at least a first stab at achieving the multi-colored stars feature. This time, it’s all tied to key macros, so no having to cycle through until I find the color I want. The way it works is through mutt’s scoring feature. At least for now, each score range (100-199, 200-299, 300-399, etc.) gets set to whatever color that score range gets. Whenever I run the macro to color a message, I pipe it (<pipe-entry>) into a bash script I wrote which greps for the Message-ID, filters out the Message-ID’s angle brackets (‘<' or '>‘), adds the relevant score, and then writes a score configuration command to a separate rc file (~/.mutt/stars). Then, I have mutt reload it’s configuration (thankfully score isn’t something that requires a complete restart).

First, the section of .muttrc I have for stars:

# Star scoring 
source ~/.mutt/stars

set my_red_star = 1000
set my_magenta_question = 800
set my_yellow_bang = 600
#set my_green_star = 400
set my_green_check = 200
set my_blue_info = 100
set my_del_star = 0

macro index,pager sr "<pipe-entry>~/bin/stars $my_red_star<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with RED"
macro index,pager sm "<pipe-entry>~/bin/stars $my_magenta_question<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with MAGENTA"
macro index,pager sy "<pipe-entry>~/bin/stars $my_yellow_bang<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with YELLOW"
macro index,pager sc "<pipe-entry>~/bin/stars $my_green_check<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with GREEN"
macro index,pager si "<pipe-entry>~/bin/stars $my_blue_info<enter><enter-command>source ~/.muttrc<enter>" "Mark the current message with BLUE"
macro index,pager sd "<pipe-entry>~/bin/stars $my_del_star<enter><enter-command>source ~/.muttrc<enter>\
<pipe-entry>~/bin/del_stars<enter>\
<enter-command>source ~/.muttrc<enter>" "Remove color marking from the current message"

color index default brightred '~n 1000-1100'  # Mark the message with red!
color index magenta default '~n 800-999'  # Mark the message with magenta!
color index black brightyellow '~n 600-799'  # Mark the message with yellow!
#color index default green '~n 400-599'  # Mark the message with green!
color index green default '~n 200-399'  # Mark the message with green (check)!
color index brightblue default '~n 100-199'  # Mark the message with blue!

And my stars script:

#!/bin/bash                                          
                                                     
msgid=$(grep -m 1 '^Message-I[Dd]' | awk '{print $2}' 
                                   | sed 's/[<>]//g')                                                                                                                                                                                        
echo "score \"~i $msgid\" $1" >> ~/.mutt/stars       

My delete stars (del_stars) script (which doesn’t work all the time, but I haven’t been able to investigate why):

#!/bin/bash

msgid=$(grep -m 1 '^Message-I[Dd]' | awk '{print $2}' | sed 's/[<>]//g')
sed -i "/$msgid/d" ~/.mutt/stars

Now the stars script doesn’t always work, either. I think I’ve tracked it down to Message-IDs which use nonalphanumeric symbols in them (like pipe ‘|’ and dollar-sign ‘$’). I might not be quoting the “~i $msgid” correctly (single-quotes, maybe?). Not terrible for a first stab at this. I wonder if any old mutt hands will have a fit if they see this, but I’m too tired to investigate further. It works well enough for my purposes right now. Also, I don’t know the performance ramifications of an ever growing ~/.mutt/stars file. We’ll have to see how that goes.