The Design of Mailprint
I wrote a tool, Mailprint, for printing out nice-looking emails from Mutt and other classic Mail user agents.
(You might remember from the last article that I have recently spent some time to polish my e-mail setup for kernel development. While this is not the hip thing to do any more, some of those mails are difficult to understand, and I occasionally print them out.)
This article describes Mailprint’s internals and design philosophy. I’m fond of this approach, because it fits nicely into the UNIX environment and is reusable.
If you are interested in using Mailprint, you can find its homepage at https://gnoack.github.io/mailprint/.
Design philosophy
Orthogonal software design, in the UNIX-style, building one tool for each task, is great. This applies in particular to side-projects, because it is a way to achieve a lot more with less work.
Mailprint is a tool which could have existed in similar form in the 80s already.
It makes use of a pipeline of other tools to do its job:
- GNU troff (
groff
) to format pages - ImageMagick’s
convert
to convert profile pictures from various image formats
Interface to the outside
To the outside, Mailprint is designed to be used as part of a UNIX pipeline, reading a plain text email and outputting PDF:
cat ~/.Mail/Inbox/cur/foobar123 | mailprint > out.pdf
This makes it easy to hook up Mailprint to mutt
and other classic MUAs.
Internal design
Internally, Mailprint generates groff source code in the “mom” dialect from the input email and feeds it through a UNIX pipeline of processing tools:
The steps implemented in Go are:
- Parsing emails into email headers and bodies. (code)
- Looking up the sender’s profile picture: This is also a separate Go library, picon.
- Converting the email to groff source code of the “mom” flavor, which is the heart of the program. (code)
The remaining steps are accomplished by invoking external UNIX programs:
- ImageMagick
convert
converts the discovered profile pictures from various source formats into the PDF format. preconv
belongs to the groff suite and converts Unicode characters into input that GNU troff understands.groff
finally creates the PDF from the input source.
The pipeline is invoked from Mailprint’s top-level run()
function. (code)
Turning it inside-out
If you want to build a more custom Mailprint pipeline, you can also make Mailprint expose its groff intermediary format using the -output.format=mom
option, and chain it with groff yourself:
mailprint -face.picon=false -output.format=mom | preconv | groff -mom -Tpdf | lpr