#002

Integrating mutt with fzf

Last updated:

For the past couple of days I’ve been hacking on my muttrc to try and find a generic way to integrate fzf in my E-Mail workflow with mutt. The idea was to create a shell script that would prompt the user to select an entry from a list using fzf, to then execute a mutt function on it1.

       function(entry)         
   ┌─────────────────────┐     
   ∨                     │     
┌──────┐  function   ┌────────┐
│ mutt │ ──────────> │ script │
└──────┘             └────────┘

To honor the unix philosophy, I ended up writing two short scripts instead of one: file_menu for selecting files and mbox_menu for selecting mailboxes. These can be used with any mutt function that requires a file or a mailbox as an argument e.g. <attach-file> or <change-folder>.

TL;DR

Usage

The scripts rely on mutt’s source command, which in addition to evaluating configuration files, it can also evaluate the output of a script when the filename is suffixed with a pipe (‘|’).

source /path/to/script|

The file_menu script is meant for selecting multiple files2. For example, it can be used with mutt’s <attach-file> function, to attach files in bulk:

$ file_menu attach-file
push <attach-file>/path/to/file_1.txt<Return>\
    <attach-file>/path/to/file_2.txt<Return>\
    <attach-file>/path/to/file_3.txt<Return>

The following macro maps the ‘a’ key3 to attach files from mutt’s compose screen using the file_menu script.

macro compose a \
'<enter-command>source "/path/to/file_menu attach-file"|<Return>' \
'attach files with fzf'

The mbox_menu script is meant for selecting a mailbox. For example, it can be used with mutt’s <change-folder> function to switch between mailboxes:

$ mbox_menu change-folder
push <change-folder>+INBOX<Return>

The following macro maps the space bar to switch between mailboxes from mutt’s index and pager screens using the mbox_menu script.

macro index,pager <Space> \
'<enter-command>source "/path/to/mbox_menu change-folder"|<Return>' \
'open a mailbox with fzf'

Source

$ cat file_menu
#!/bin/sh

FILES=$(fzf --height=100% --multi)

printf 'push '
for i in $FILES
do
    [ -f "$i" ] && printf '<%s>%s<Return>' "$1" "$i"
    [ -d "$i" ] && find "$i"/* -type f -maxdepth 0 \
        -exec printf '<%s>%s<Return>' "$1" {} \;
done
$ cat mbox_menu
#!/bin/sh

list()
{
    # your command to list mailboxes
}

MAILBOX=$(list | fzf --height=100% | sed 's/ /%20/g')

if [ -n "$MAILBOX" ]
then
    printf 'push <%s>+%s<Return>' "$1" "$MAILBOX"
fi

Ideas

These scripts are not limited to the examples shown here. After all, the idea was to make them as generic as possible for them to be flexible and reusable. Below are some other ideas on how these scripts can be used:


  1. This was inspired by a gist on GitHub 

  2. Using fzf’s –multi flag 

  3. Mutt’s default key to attach a file