The goal
I want to create emails that look their best in all mail clients, whether graphical or text based. Ideally I’d write a message in a simple format like Markdown, and generate the final email from the input file. Additionally, I’d like to be able to include fenced code snippets in the message, and make them available as attachments.
Demo
I created a utility called mimedown that reads markdown through stdin and prints multipart MIME to stdout.
Let’s see it in action. Here’s an example message:
## This is a demo email with code
Hey, does this code look fishy to you?
```crash.c
#include <stdio.h>
int main(void)
{
char a[] = "string literal";
char *p = "string literal";
/* capitalize first letter */
p[0] = a[0] = 'S';
printf("a: %s\np: %s\n", a, p);
return 0;
}
```
It blows up when I compile it and run it:
```compile.txt
$ cc -std=c99 -pedantic -Wall -Wextra crash.c -o crash
$ ./crash
Bus error: 10
```
Turns out we're invoking undefined behavior.
* The C99 spec, appendix J.2 Undefined Behavior mentions this case:
> The program attempts to modify a string literal (6.4.5).
* Steve Summit's C FAQ [question 1.32](http://c-faq.com/decl/strlitinit.html)
covers the difference between an array initialized with string literal vs a
pointer to a string literal constant.
* The SEI CERT C Coding standard
[STR30-C](https://wiki.sei.cmu.edu/confluence/display/c/STR30-C.+Do+not+attempt+to+modify+string+literals)
demonstrates the problem with non-compliant code, and compares with compliant
fixes.
After running it through the generator and emailing it to myself, here’s how the result looks in the Fastmail web interface:
Notice how the code blocks are displayed inline and are available as attachments with the correct MIME type.
I intentionally haven’t configured Mutt to render HTML, so it falls back to the
text alternative in the message, which also looks good. Notice how the message
body is interleaved with Content-Disposition: inline attachments for each
code snippet.
The email generator also creates references for external urls. It substitutes
the urls in the original body text with references, and consolidates the links
into a bibliography of type text/uri-list at the end of the message. Here’s
another Mutt screenshot of the end of the message, with red circles added.
The generated MIME structure of our sample message looks like this:
I 1 <no description> [multipa/alternativ, 7bit, 3.1K]
I 2 ├─><no description> [multipa/mixed, 7bit, 1.7K]
I 3 │ ├─><no description> [text/plain, 7bit, utf-8, 0.1K]
I 4 │ ├─>crash.c [text/x-c, 7bit, utf-8, 0.2K]
I 5 │ ├─><no description> [text/plain, 7bit, utf-8, 0.1K]
I 6 │ ├─>compile.txt [text/plain, 7bit, utf-8, 0.1K]
I 7 │ ├─><no description> [text/plain, 7bit, utf-8, 0.5K]
I 8 │ └─>references.uri [text/uri-list, 7bit, utf-8, 0.2K]
I 9 └─><no description> [text/html, 7bit, utf-8, 1.3K]
At the outermost level, the message is split into two alternatives: HTML and multipart/mixed. Within the multipart/mixed part is a succession of message text and code snippets, all with inline disposition. The final mixed item is the list of referenced urls (if necessary).
Other niceties
Lines of the message body are re-flowed to at most 72 characters, to conform to historical length constraints. Additionally, to accommodate narrow terminal windows, mimedown uses a technique called format=flowed. This is a clever standard (RFC 3676) which adds trailing spaces to any lines that we would like the client reader to re-flow, such as those in paragraphs.
Neither hard wrapping nor format=flowed is applied to code block fences in the original markdown. Code snippets are turned into verbatim attachments and won’t be mangled.
Finally, the HTML version of the message is tasteful and conservative. It should display properly on any HTML client, since it validates with ISO HTML (ISO/IEC 15445:2000, based on HTML 4.01 Strict).
Try it yourself
Clone it here: github.com/begriffs/mimedown. It’s written in portable C99. The only build dependency is the cmark library for parsing markdown.