A friend has got me thinking about using Mutt again. I gave it up years ago after I was forced to use IMAP for one of my mail accounts, and I didn’t think Mutt was up to the task. I switched to Thunderbird, which lets me do certain things faster. However, I’ve really missed a few features from Mutt: textual and portable configuration files, multiple message replies, and full Vim support.
As I return to Mutt, I also miss a few things from Thunderbird. The most prominent of these is autocompletion of my recipients. Mutt will tab-complete aliases that you’ve previously registered in its configuration files, but Thunderbird one-ups Mutt by automatically storing the addresses of people you send messages to. I wanted to make Mutt do that too.
I looked around for hooks, but I didn’t see a way for Mutt to automatically record aliases when I sent a message. However, since I was using Vim to edit my messages, I saw that I could create an autocommand that would strip out the recipients’ addresses from my message and append them to my alias file. So, I first wrote a function to do the heavy-lifting:
" This function, which is to be run only on a Mutt email message, " finds all the addresses in the To, Cc, and Bcc headers. If " no aliases exist for these addresses, they are added to the " alias file. function! AddMuttAliases() " This is where my alias file lives. Change this to something " that suits you. let aliasfile = $UU . '/configs/mutt/aliases' " Why isn't there a match + matchstr? match only gives me the " start, which is not enough to extract the substring. " matchstr doesn't give me the location, which is not enough " information to advance forward. " Find all email addresses. My pattern may not be the best yet. let addresses =  silent vimgrep /^\(To\|Cc\|Bcc\):/j % for line in getqflist() let pattern = '[-A-z._]\+@[-A-z._]\+' let start = match(line.text, pattern) let address = matchstr(line.text, pattern, start) while address != "" call add(addresses, address) let start += len(address) let address = matchstr(line.text, pattern, start) endwhile endfor " Check to see if each is in aliases file. If not, add it. " Mutt's alias registration command has this form: " " alias name address " " Usually the name is something short and mnemonic. I prefer " to continually work with people's addresses so that I'm not " too crippled when I lose my configuration. So, my aliases " have this form: " " alias address address " " Isn't this overly verbose? Yes. What have I gained? Well, " mutt will tab-complete the addresses for me. Verbosity " doesn't matter. And that's sweet. for address in addresses execute 'silent! vimgrep /' . address . '/j ' . aliasfile if len(getqflist()) == 0 let aliasline = 'alias ' . address . ' ' . address silent! execute '!echo ' . aliasline . ' >> ' . aliasfile endif endfor endfunction
To call this function when Mutt messages are written, I registered the following autocommand in my .vimrc file:
autocmd BufWritePost ~/.tmp/mutt-* call AddMuttAliases()
This command assumes Mutt messages are temporarily stored in ~/.tmp, which I set in my .muttrc.
Now everytime I write a message to someone new, I get an alias added to my aliases file. The next time, I can simply tab-complete to enter the person’s address!