I am a fan of Mutt, a command line email client. It is really powerful, and it is highly customizable. Configuring it can be difficult due to having so many settings, but there are quite a few decent tutorials online for learning to configure it and any related commands.

Mutt used to have to rely on other programs in order to send and receive mail on a remote server. But it has been possible for a while now to use its own built-in support for POP and IMAP for receiving mail, and SMTP for sending mail. Normally, if you did not want to have to type in your password every time you connected, or if you use several different accounts, you would have to store your password(s) in your mutt configuration files in clear text. It would be nice if security storing services like Mac OS X’s Keychain, Gnome’s Keyring, or KDE’s kWallet could be used natively within Mutt, but that is not yet the case. Under Mac OS X, however, passwords can be stored in the Keychain and accessed from the command line with the security command, and Mutt configuration files can call snippets of shell code that will get replaced with the output of the shell commands.

This article explains a basic approach on how to use the security command, and a basic way of using it in a Mutt configuration file. I may present the Ruby wrapper script that I actually use in a future article.

Setting up Keychain

First, the password needs to be added to login.keychain or another keychain file for the current user. Run /Applications/Utilities/Keychain Access.app, and select New Password Item… from the File menu. This will bring up a dialog where the account info and password can be filled in.

The 'New Password Item' dialog

The protocol and server name should be filled in using URL syntax, such as imap://imap.someserver.com. Don’t worry about whether the server uses the SSL/TLS variation of the email network protocols or not because we will configure that in Mutt based on the protocols used. The protocol and server name are needed to look up the password in the keychain database.

Next, verify that the Keychain item is correctly filled out:

The new Keychain item

security Command Basics

According to its man page, security is a “command line interface to keychains and Security.framework.” It provides a crude way to look up Keychain entries. Like most of Apple’s command line tools, it provides several actions that can be performed, but the one useful here is find-internet-password.

A query will look something like:

$ security find-internet-password -g -a someuser@example.com -s imap.example.com
  • -g makes it output the password to stderr, in addition to the normal info to stdout
  • -a is the account name to look up
  • -s is the server name to lookup

There are other options that can be used to look up a Keychain entry, but the above two are sufficient for most needs (see the man page for more options).

The first time security is run, the Mac OS will ask whether to allow security access the queried password or not. If it is allowed to do so once (in which case every time it access a given entry it will have to be granted permission once) or always, it will print something like the following:

keychain: "/Users/someuser/Library/Keychains/login.keychain"
class: "teni"
attributes:
    0x00000007 <blob>="imap.example.com"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="someuser@example.com"
    "atyp"<blob>="dflt"
    "cdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Zkeychain: "/Users/someuser/Library/Keychains/login.keychain"
class: "teni"
attributes:
    0x00000007 <blob>="imap.example.com"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="someuser@example.com"
    "atyp"<blob>="dflt"
    "cdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Z\000"
    "crtr"<uint32>=<NULL>
    "cusi"<sint32>=<NULL>
    "desc"<blob>=<NULL>
    "icmt"<blob>=<NULL>
    "invi"<sint32>=<NULL>
    "mdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Z\000"
    "nega"<sint32>=<NULL>
    "path"<blob>=<NULL>
    "port"<uint32>=0x00000000
    "prot"<blob>=<NULL>
    "ptcl"<uint32>="imap"
    "scrp"<sint32>=<NULL>
    "sdmn"<blob>=<NULL>
    "srvr"<blob>="imap.example.com"
    "type"<uint32>=<NULL>
password: "somepassword"
00"
    "crtr"<uint32>=<NULL>
    "cusi"<sint32>=<NULL>
    "desc"<blob>=<NULL>
    "icmt"<blob>=<NULL>
    "invi"<sint32>=<NULL>
    "mdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Zkeychain: "/Users/someuser/Library/Keychains/login.keychain"
class: "teni"
attributes:
    0x00000007 <blob>="imap.example.com"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="someuser@example.com"
    "atyp"<blob>="dflt"
    "cdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Z\000"
    "crtr"<uint32>=<NULL>
    "cusi"<sint32>=<NULL>
    "desc"<blob>=<NULL>
    "icmt"<blob>=<NULL>
    "invi"<sint32>=<NULL>
    "mdat"<timedate>=0x32303039313031393030303330305A00  "20091019000300Z\000"
    "nega"<sint32>=<NULL>
    "path"<blob>=<NULL>
    "port"<uint32>=0x00000000
    "prot"<blob>=<NULL>
    "ptcl"<uint32>="imap"
    "scrp"<sint32>=<NULL>
    "sdmn"<blob>=<NULL>
    "srvr"<blob>="imap.example.com"
    "type"<uint32>=<NULL>
password: "somepassword"
00"
    "nega"<sint32>=<NULL>
    "path"<blob>=<NULL>
    "port"<uint32>=0x00000000
    "prot"<blob>=<NULL>
    "ptcl"<uint32>="imap"
    "scrp"<sint32>=<NULL>
    "sdmn"<blob>=<NULL>
    "srvr"<blob>="imap.example.com"
    "type"<uint32>=<NULL>
password: "somepassword"

Make sure it is finding the correct password. If there is more than one entry for the same domain/account pair, the service type may need to be specified, or one of the found entries should be renamed or removed from the Keychain.

Getting Just the Password

The only part of the output that is desired is the password itself. Sed, awk, or grep could be used, but perl will be used here to make it so that the only text on stdout is the password itself.

security find-internet-password -g -a someuser@example.com -s imap.example.com 2>&1\
| perl -e 'if (<STDIN> =~ m/password: "(.*)"$/ ) { print $1; }'

This could be put directly into a Mutt configuration file, or it could be put in a script.

Incorporating it into Mutt

For a simple single account muttrc file, one could do the following:

set smtp_user="someuser@example.com"
set smtp_pass=`security find-internet-password -g -a someuser@example.com -s imap.example.com 2>&1 | perl -e 'if (<STDIN> =~ m/password: "(.*)"$/ ) { print $1; }'`
set imap_user="someuser@example.com"
set imap_pass=`security find-internet-password -g -a someuser@example.com -s imap.example.com 2>&1 | perl -e 'if (<STDIN> =~ m/password: "(.*)"$/ ) { print $1; }'`

Or to reduce the number of times security gets called:

set my_pass=`security find-internet-password -g -a someuser@example.com -s imap.example.com 2>&1 | perl -e 'if (<STDIN> =~ m/password: "(.*)"$/ ) { print $1; }'`
set smtp_user="someuser@example.com"
set smtp_pass=$my_pass
set imap_user="someuser@example.com"
set imap_pass=$my_pass

And that’s it. I actually use a Ruby wrapper around security, which uses a lockfile to prevent multiple instances of security from asking to unlock the keychain at the same time (I also use offlineimap, which calls the same script for the passwords). I may publish that script at some point.