My Heirloom mailx setup

Update, 2017

On Christmas I ended up reading RFC 5322 and, after some consideration, decided to write my own MUA. Inspired by software such as ed and mailx, I named my program edmail. It is available at NotABug, and is written in reasonably portable sh. The following discussion shall, however, be preserved here.


For several years I used Mutt for my mail and, while it worked really well, I never felt too comfortable using it. Upon migrating to another host I decided to try something else: Heirloom mailx. It quickly replaced Mutt as my preferred mail client.

I had used mailx previously for system mail, but never really thought of it as a serious contender amidst all modern mail clients. However, running twm (which dates back to 1987) as my window manager, age simply was not an acceptable excuse to not give mailx a fair chance, and I have always found simplicity a desirable property.

I must not be misunderstood, however; mailx is a very powerful and configurable MUA. Simplicity does not imply a lack of features and it is the all too rare combination of these aforementioned qualities that the truly great pieces of software share.


Compiling mailx is simple and takes almost no time on a modern computer. Configuring it may, on the other hand, take hours or even days. This page provides a simple reference to a configuration I use. Without further ado, my .mailrc:

# macro definitions

define sort {
    move :r (from <univ host>) +Archive/University
    move :r (or to openbsd cc openbsd) +Archive/OpenBSD
    move :r +Archive/Main
    flag (larger 25000)

# binary options

set autothread bsdcompat emptybox outfolder sendwait

# string options

set folder=imaps://<user>@<imaphost>
set password-<user>@<imaphost>="<passwd>"
set ssl-verify=strict
set record=+Sent
set smtp-auth=plain
set smtp=smtps://<smtphost>
set smtp-auth-user=<user>
set smtp-auth-password="<passwd>"

set imap-keepalive=1200
set imap-cache=~/.cache/mailx
set folder-hook-imaps://<user>@<imaphost>/Inbox=sort

set from="<name> <<email>>"
set sign="-- \n  <name>\n  PGP: <long id>\n  <url>"
set cmd="gpg --decrypt --pinentry-mode loopback"
set VISUAL=/usr/bin/vim
set sendcharsets=utf-8
set escape=.

# commands

source ~/.aliases

shortcut in +Inbox
shortcut out +Sent
shortcut main +Archive/Main
shortcut bsd +Archive/OpenBSD
shortcut uni +Archive/University

retain date from to cc subject user-agent content-type
fwdretain date from to subject

First I define a macro that helps me keep my mailbox in order; its function is explained in the following paragraph. Consult the mailx manual for the binary options I have set below the macro definition.

Most of the string options are self-explanatory, but a few comments are in order. The folder hook on Inbox makes use of the sort macro: it moves all read messages to different subfolders of the Archive mailbox, based on criteria set in the definition of the macro. It also flags every message larger than 25 kilobytes, thus making it easy to identify messages that take up more space on the mail server.

I keep a file of aliases and source it at startup. Aliases allow me to send mail by simply typing mailx <alias> at the shell prompt. The shortcut block defines shortcuts to conveniently change the current mailbox directory. For example, typing fi bsd at the mailx prompt takes me to the folder containing the archived messages of the OpenBSD mailing list I am subscribed to.

The last block defines the headers I prefer to be visible in the messages I receive and forward, respectively.

Remarks on mailx and GPG

While I get to exchange encrypted mail only too rarely, I require the ability to do so in a convenient manner. Initially I expected some drawbacks with mailx on this front.

Surprisingly, however, the piping commands of mailx make dealing with GPG effortless; one can use the tilde escape ~| to encrypt and sign messages and, in similar fashion, the pipe command can be used to decrypt and verify. Note that newer versions of gpg may require the loopback pinentry mode (or pinentry-tty).