From 1f413b099c7d5ead0589b92ce4ca377125a24caa Mon Sep 17 00:00:00 2001 From: Daniel Fichtinger Date: Sun, 13 Jul 2025 18:25:30 -0400 Subject: [PATCH] added email-formatting draft post --- content/blog/email-formatting.md | 189 +++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 content/blog/email-formatting.md diff --git a/content/blog/email-formatting.md b/content/blog/email-formatting.md new file mode 100644 index 0000000..0f97e80 --- /dev/null +++ b/content/blog/email-formatting.md @@ -0,0 +1,189 @@ +--- +title: Email Formatting Is Harder Than It Looks +date: 2025-07-13 +draft: true +--- + +*[UTF-8]: Unicode Transformation Format - 8 bit. + +[Kakoune]: https://kakoune.org + +As I've [mentioned before](./email-in-kakoune.md), I like using [Kakoune] for +reading & writing emails. Of course, Kakoune is a text editor, not a _rich text_ +editor. It operates on UTF-8 _plaintext_ --- which means that the emails I write +need to be in plaintext, too. + +As I went down this path, I quickly discovered that I needed an **email +formatter**. I eventually wrote [`mailfmt`](https://git.sr.ht/~ficd/mailfmt) to +fill this niche. It provides consistent paragraph spacing, hard-wrapping and +paragraph reflow, while preserving Markdown syntax, email headers, quotes, +sign-offs, and signature blocks. Additionally, the wrapped output can be made +safe for passing to a Markdown parser. This is useful if you want to build an +HTML email from plain-text. + +`mailfmt` open-source under the ISC license, and is available on +[PyPI](https://pypi.org/project/mailfmt/) for installation with tools like +`pipx` and `uv`. The source code is available on sourcehut at +[git.ficd.sh/ficd/mailfmt](https://git.ficd.sh/ficd/mailfmt). + +## Target Audience + +I wrote this tool primarily for myself. It's served me very well over the past +few months. `mailfmt` could be helpful for anyone that prefers writing email in +plain-text using text editors like Kakoune, Helix, and Vim. It can format via +`stdin`/`stdout` and read/write files, making `mailfmt` easy to configure as a +formatter for the `mail` filetype in your editor. + +I'm including a very lengthy explanation of exactly why I built this tool. You +may think it's overkill for such a small program — but I like to be crystal +clear about justifying my work. It reads like blog post rather than the +emoji-filled `README`/marketing style we're accustomed to seeing on this +platform. I've put a lot of thought into this, and I want to share my work. I +hope you enjoy reading about my thought process. + +## Why I Built It (Comparison) + +Unsurprisingly, it all started with a specific problem I was having composing +emails in plain-text format in my preferred text editor. As I searched for a +solution, I couldn't find anything that met all my needs, so I wrote it myself. + +Here's what I wanted: + +- A way to consistently format my outgoing emails in my text editor. +- Paragraph reflow and automatic line wrapping. + - Not all plain-text clients are capable of line-wrap. In some contexts, such + as mailing lists, the author is expected to wrap the text themselves. +- Inline Markdown syntax `can _still_ look great, **even** in plain-text!` Thus, + I wanted to use it: + - Without it being broken by reflow & wrap. + - While looking good and retaining the same semantics in _both_ rendered + **and** plain-text form — ideal for `multipart` emails. +- Ensure signature block is formatted properly. + - The single space after `--` and before the newline **must** be included. + +### `fmt` and Markdown Formatters Don't Work For Email + +The `fmt` utility provides great wrapping and reflow capabilities — I use it all +the time while writing LaTeX. However, it's syntax agnostic, and breaks +Markdown. For example, it completely mangles fenced code blocks. I figured: hey, +why not just use a Markdown formatter? It supports Markdown (obviously), _and_ +can reflow & wrap text! Here's the problem: it turns out treating your +**entire** email as a Markdown document isn't ideal. + +`mailfmt`'s approach is simple: detect when a line matches a known pattern of +Markdown block element syntax, such as leading `#` for headings, `-` for lists, +etc. If so, **leave the line untouched**. Similarly, **don't format anything +inside fenced code blocks**. + +#### Sign-Offs + +Consider the following sign-off: + +``` +Best wishes, +Daniel +``` + +A Markdown formatter considers this to be one paragraph, and reflows it +accordingly, causing it to lost semantic meaning: + +``` +Best wishes, Daniel +``` + +Within the confines of Markdown, I counted three ways of dealing with the +problem: + +1. Put an empty line between the two parts: + +``` +Best wishes, + +Daniel +``` + +> However, this empty line looks _awkward_ when viewed in plain-text. + +2. Put a backslash after the intentional line break: + +``` +Best wishes, \ +Daniel +``` + +> Again, this looks bad when the Markdown isn't rendered. + +3. Put two spaces after the intentional line break (• = space): + +``` +Best•wishes,•• +Daniel +``` + +> This syntax is **ambiguous, easy to forget**, and **not supported by editors +> that trim trailing whitespace.** + +`mailfmt` detects sign-offs using a very simple heuristic. First, we check if a +line has _5 or less_ words, and **ends with a comma**. If we find such a line, +we check the _next_ line. If it has 5 or less words **that all begin with an +uppercase letter**, then we assume these two lines are a _sign-off_, and we +don't reflow or wrap them. The heuristic matches a very simple pattern: + +``` +A courteous greeting, +First Middle Last Name +``` + +#### Signature Block + +The convention for signature blocks is as follows: + +1. Begins with two `-` characters followed by a single space, then a newline. +2. Everything that follows until the EOF is part of the signature. + +Here's an example (note the • = space): + +``` +--• +Daniel + +Software•Developer,•Company +email@website.com +``` + +As with sign-offs, such a signature block gets mangled by Markdown formatters. +Furthermore, the single space after the `--` token is important: if it's +missing, some clients won't recognize it is a valid signature — our formatter +should address this too. + +`mailfmt` detects when a line's _only_ content is `--`. It adds the required +trailing space if it's missing, and it treats the rest of the input as part of +the signature, leaving it completely untouched. + +### Consistent Multipart Emails + +Something you may want to do is generate a `multipart` email. This means that +_both_ an HTML **and** plain-text representation of the _same_ email are +included in the file — leaving it up to the reader's client to pick which one to +display. + +The plain-text email **must** be able to stand on its own, and _also_ render to +decent-looking HTML. Essentially, you want to write your email in plain-text +once, ensuring it has proper formatting, and then use a command to generate an +HTML email from it. For this, `mailfmt` provides the `--markdown-safe` flag, +which appends backslashes to the formatted output, making it safe for Markdown +parsing without messing up the line breaks after sign-offs and signature blocks. + +For example, I use the following in [aerc](https://aerc-mail.org/) to generate +an HTML multipart email whenever I want: + +```ini +[multipart-converters] +text/html=mailfmt --markdown-safe | pandoc -f markdown -t html --standalone +``` + +## Conclusion + +If you've made it this far, thanks for sticking with me and reading to the end! +Even if you don't plan to write plain-text email or use `mailfmt` at all, I hope +you learned something interesting.