The Design of Mailprint
(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/.
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
convertto 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.
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:
convertconverts the discovered profile pictures from various source formats into the PDF format.
preconvbelongs to the groff suite and converts Unicode characters into input that GNU troff understands.
grofffinally 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