hi, it's mike ʕ•ᴥ•ʔノ

Daily notes for 2024-01-09 (mutt noodling edition)

Multi-account, GPG-secured mutt config

I keep having to reinvent this every few years, and I always stitch it together from assorted sources, mostly because Google sort of shifts around now and then. So:

There are all sorts of ways to handle mutt config for assorted providers. The examples here are working right now, in early 2024. They probably have bits of cruft and lint because my config has been a work in progress since some time in the late 20th century.

Overview

You’re making profiles to do this: One for each of your accounts that will hold account specific config information. If you currently have a monolith config in mutt, you can lift a lot of stuff out of it and move it into a profile, then source the profile in your main muttrc.

You’re also going to make and encrypt a credential file for each account. Some people do this all in one file and use account hooks to make sure imap_user, imap_password and smtp_password are set correcctly depending on the account you’re operating in. I chose to make a file for each account.

You’re going to make macros that source the profiles when you want to switch between them.

0. Pre-config with Gmail and Fastmail

I’m not going to go into a ton of detail here:

For Fastmail:

1. The profile files

Make profile files for each of your accounts. I name them workplace.profile, fastmail.profile, etc. It doesn’t matter there’s no required convention. It’s a good idea to use the first one as the template for the second one.

This is an example of my Fastmail profile. Note line 6:

source "gpg -d ~/.mutt/passwords.gpg |"

That’s where your credentials will come from. I’ll show that file next.

 1# -*- muttrc -*-
 2# Mutt sender profile : personal/default
 3
 4unset folder
 5set smtp_authenticators = 'gssapi:login' # fastmail needs this
 6set imap_authenticators = ''
 7source "gpg -d ~/.mutt/passwords.gpg |" 
 8set spoolfile = "imaps://imap.fastmail.com"
 9set folder = "imaps://imap.fastmail.com/INBOX"
10set postponed="+Drafts"
11set hostname="yourdomain.com"
12set signature= "~/.mutt/personal.sig"
13set from= "Bob Jones <[email protected]>"
14set realname = "Bob Jones"
15set smtp_url = "smtps://[email protected]@smtp.fastmail.com:465" # use your fastmail username, not your email address
16set imap_user = "[email protected]" # use your fastmail username here, too
17
18# set the status to show which profile I'm using
19set status_format= "-%r-Fastmail: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---\n"
20
21unmy_hdr *
22
23my_hdr From: Bob Jones <[email protected]>
24my_hdr Organization: yourdomain.com
25my_hdr Sender: Bob Jones <[email protected]>
26my_hdr Return-Path: <[email protected]>
27
28# clear the existing mailboxes list
29unmailboxes *
30
31# load up mailboxes appropriate to this profile
32mailboxes + "=Spam"
33mailboxes + "=disposable"
34mailboxes + "=Newsletters"
35mailboxes + "=Sent"
36mailboxes + "=Archive"

2. Make credentials files

For each account, you need to make a file for your credentials.

set [email protected]
set imap_pass="klatu barada nikto"
set smtp_pass="klatu barada nikto"

Name it whatever. passwords-accountname works.

Once you’ve created the file, encrypt it with gpg:

gpg -r [email protected] -e passwords-fastmail

Test it:

gpg -d passwords-fastmail.gpg

Then shred the plaintext original:

shred -u passwords-fastmail

Make sure that your profile (from the previous step) is sourcing the gpg file in line 6 of my example, e.g.

source "gpg -d ~/.mutt/passwords-fastmail.gpg |"

3. Do a quick mid-config check

Might as well test it now. You can do that by sourcing one of your profiles in your muttrc:

source ~/.mutt/fastmail.profile

When you run mutt the first time in this login session, you should get a gpg prompt for your credentials so mutt can decrypt your password file and use it to log in.

If it’s working, now’s the time to make your second profile and credentials files using the above steps since it’ll be good to know what they’re all called for the next step, which is making macros.

4. Make macros

I keep my macros in their own file under ~/.mutt just to keep things modular. You can put these in your main muttrc. Whatever you prefer. If you have a separate file, make sure to source it in muttrc:

source ~/.mutt/macros

Now add something like this for each account:

macro index .cf '<sync-mailbox><enter-command>source ~/.mutt/fastmail.profile<enter><change-folder>!<enter>'
macro index .cg '<sync-mailbox><enter-command>source ~/.mutt/google.profile<enter><change-folder>!<enter>'

That just does one last sync, then sources your profile, then changes folders to the inbox of that profile.

Restart mutt. From the index, if all is working correctly, the macro .cf will source your fastmail.profile and the macro .cg will source your google.profile file (both of which also source/decrypt their respective credential files).

5. In conclusion

Once it’s all wired up and running, you should be able to switch back and forth between accounts with just a few seconds of latency as the inbox syncs on exit and the new inbox syncs on login.

The pleasures of mutt

I went on a mutt revival kick early last year. It remains a land of contrasts. I never end up sticking to it 100 percent of the time but instead prefer to use it as a quick triage tool: It’s easy to make macros and keybindings that speed up inbox processing. Sometimes it’s easier to just bail out to the web mail interface, but during the day it’s helpful to just burn through the inbox never taking my hands off the keyboard.

mutt scoring and color treatments

One last thing, I guess, since I’m documenting stuff. One of the reasons I like mutt for triage so much is my ability to add a little visual treatment to messages based on their scores. That makes it easy to see what in my inbox has more priority.

I’ve got this little script in my ~/.mutt:

 1#!/usr/bin/env ruby
 2
 3require 'mail'
 4require 'tempfile'
 5
 6# Wants a +/- integer, e.g. +20
 7score = ARGV.first
 8
 9score_file = "#{Dir.home}/.mutt/scored"
10
11msg = Tempfile.new('msg')
12
13msg.write($stdin.read)
14
15mail = Mail.read(msg)
16
17from = mail.from.first
18
19File.open(score_file, "a") { |f| f.write "score ~f#{from} #{score}\n"}
20
21msg.close
22
23msg.unlink

And I’ve got these macros in my ~/.mutt/macros file:

1# Score messages
2macro index,browser .sp "<pipe-entry>~/.mutt/mailscore.rb +5\n<enter-command>source ~/.mutt/scored<enter>" # score sender +5
3macro index,browser .sP "<pipe-entry>~/.mutt/mailscore.rb +20\n<enter-command>source ~/.mutt/scored<enter>" # score sender +20
4macro index,browser .sm "<pipe-entry>~/.mutt/mailscore.rb -5\n<enter-command>source ~/.mutt/scored<enter>" # score sender -5
5macro index,browser .sM "<pipe-entry>~/.mutt/mailscore.rb -20\n<enter-command>source ~/.mutt/scored<enter>" # score sender -20

And I’ve got a few lines in my ~/.mutt/colors file:

1color index cyan default "~n 0-2 !~p"
2color index magenta default "~n <5"
3color index brightyellow default "~n >15"
4color index brightred default "~n >19"
5#

The macros pipe a given message into the script, the script extracts the sender, and the script writes a line into my ~/.mutt/scored file. Then the ~/.mutt/colors file (which you need to source in muttrc) assigns colors to certain scores. I have a few other rules in ~/.mutt/scores, as well:

1# Date-based scoring penalties -- older things fall down
2score ~d>3d -1
3score ~d>7d -3
4score ~d>14d -10
5
6score "~O" +10 # old = +10 so I don't miss it
7score "~F" +20 # flagged = +20 so it stays in the interesting view for a while, even if old
8score "!~p ~d>7d" -10 # not for me directly, getting old, let it fade away
9score "!~l" +2 # to a known list, give it a bump

#Journal #Mutt #Linux #Gpg #Email #Cli #Ruby