256 lines
8.1 KiB
Markdown
256 lines
8.1 KiB
Markdown
---
|
|
title: Writing Emails In Helix
|
|
date: 2025-05-29
|
|
---
|
|
|
|
This article is all about writing emails in Helix. Obviously, Helix isn't an
|
|
email client -- and it's lacking in a plugin system, so you can't really turn it
|
|
into one, either. And that's okay! You might be wondering, then, what exactly do
|
|
I mean by "writing emails in Helix"?
|
|
|
|
An email client needs to do a whole lot more than write text! It needs to
|
|
connect to your mail servers, show your messages, display and allow you to
|
|
interact with flags/labels, be able to **send** your email, etc. Only an insane
|
|
person would try to hamfist this functionality into a text editor (I'm looking
|
|
at you, Neovim plugin developers!).
|
|
|
|
Helix is **really** good at its _one_ job, and that's **editing text**. It is a
|
|
text editor, after all. As it turns out, _writing_ emails is, well, text
|
|
editing, which is Helix's forte. So why not take Helix's amazing writing
|
|
experience, and apply it to email? If you're willing to take the plunge, you may
|
|
be pleasantly surprised at how **joyful** writing email can actually be!
|
|
|
|
There are a few different ways to approach composing emails in Helix. This post
|
|
covers what worked best for me. That is, using Helix as a composer for the
|
|
`aerc` email client. It wasn't straightforward to figure out at first, but
|
|
all-in-all, the configuration isn't actually that complicated, so you should be
|
|
able to set it up in no time.
|
|
|
|
<!--toc:start-->
|
|
|
|
- [Aerc Integration](#aerc-integration)
|
|
- [Naive Approach](#naive-approach)
|
|
- [Helix Workspace](#helix-workspace)
|
|
- [Markdown Highlighting](#markdown-highlighting)
|
|
- [Spellcheck](#spellcheck)
|
|
- [Formatting](#formatting)
|
|
- [Conclusion](#conclusion)
|
|
|
|
<!--toc:end-->
|
|
|
|
## Aerc Integration
|
|
|
|
At the end of the day, an email is just a text file. An `.eml` file, to be
|
|
exact. So, you _could_ just open up a fresh buffer, manually type in your
|
|
headers, and go to town. When you're done, you can figure out _some_ way to
|
|
actually send that file (perhaps dragging and dropping it into your mail
|
|
client).
|
|
|
|
However, that's not really ideal. For starters, emails have a **lot** of
|
|
headers, and if you mess any of them up, your message might not get delivered.
|
|
You probably want to be able to, at the very least, **reply** to an email and
|
|
have its headers be auto-filled.
|
|
|
|
Therefore, some level of integration with an actual email client is desirable.
|
|
Let the client handle every _other_ aspect of reading and sending email, and
|
|
relegate **writing** to Helix. This is the approach I'll be covering.
|
|
|
|
## Naive Approach
|
|
|
|
The simplest approach should work with zero configuration. `aerc` uses your
|
|
`$EDITOR` to compose your emails by default; so you can get started using Helix
|
|
right away! However, this is missing two important features: **spellchecking**
|
|
and **formatting**. To that end, we have to figure out how to get Helix to load
|
|
a custom configuration for emails.
|
|
|
|
## Helix Workspace
|
|
|
|
As you may know, Helix gives you an option to specify _per-project_
|
|
configuration. This requires creating a `.helix` directory in the root of your
|
|
project, and filling it with `config.toml` and `languages.toml` files that
|
|
override your default config. _However_, there isn't currently a way to specify
|
|
_filetype-specific_ options; this is where we have to get creative.
|
|
|
|
I recommend creating a folder inside your `aerc` config called `helix-config`.
|
|
Its name doesn't actually matter, so you can call it whatever you want! This
|
|
directory will serve as our _workspace_. The basic idea is to have `aerc` open
|
|
email files with this directory set as the current working directory — which is
|
|
what induces Helix to load the workspace config.
|
|
|
|
Inside our new workspace, let's create the `.helix` directory and populate
|
|
`config.toml` with our preferences:
|
|
|
|
```toml
|
|
[editor]
|
|
text-width = 74
|
|
[editor.soft-wrap]
|
|
enable = true
|
|
wrap-at-text-width = true
|
|
```
|
|
|
|
The final step is the simplest. First, create a shell script inside
|
|
`helix-config`:
|
|
|
|
```bash
|
|
#!/bin/sh
|
|
|
|
cd ~/.config/aerc/helix-config && hx "$@"
|
|
```
|
|
|
|
This will serve as our "email entry point". It simply sets the CWD to our new
|
|
workspace, then loads Helix normally. Then, you'll need to set the `editor`
|
|
option in `aerc.conf`:
|
|
|
|
```ini
|
|
[compose]
|
|
editor=/home/yourUserName/.config/aerc/helix-config/hx.sh
|
|
```
|
|
|
|
Unfortunately, you have to provide an absolute path, otherwise `aerc` won't find
|
|
the script.
|
|
|
|
## Markdown Highlighting
|
|
|
|
When writing plain-text emails, I like to use Markdown markup. Consider the
|
|
following message:
|
|
|
|
```
|
|
Dear John,
|
|
|
|
Thanks for sharing! I _seriously_ appreciate your help.
|
|
|
|
To proceed, we'll need to do:
|
|
|
|
- Thing A
|
|
- Thing B
|
|
```
|
|
|
|
Even though the recipient will receive this email in un-rendered plain text
|
|
format, the _semantics_ are still very clear. Of course, we don't _need_
|
|
highlighting in our editor to write markdown, but it can help make the
|
|
experience a bit better.
|
|
|
|
All you need to do is create a `.helix/languages.toml` file inside our email
|
|
workspace from before:
|
|
|
|
```toml
|
|
[[language]]
|
|
name = "markdown"
|
|
file-types = [{ glob = "/tmp/aerc-compose-*.eml" }]
|
|
```
|
|
|
|
Take note of the `file-types` entry. Email compose files opened by `aerc` will
|
|
always match the `/tmp/aerc-compose-*.eml` pattern. The above snippet ensures
|
|
that emails will be treated as Markdown files by Helix. The reason I recommend
|
|
putting this in your _workspace_ config and not setting it globally is to avoid
|
|
complications if you ever find yourself needing to edit a regular `.eml` file
|
|
_outside_ of `aerc`.
|
|
|
|
## Spellcheck
|
|
|
|
The excellent [harper](https://github.com/Automattic/harper) LSP supports
|
|
Markdown out-of-the-box. You can follow the instructions in its documentation to
|
|
install and configure it for Helix. Then, you can add it to your workspace
|
|
`languages.toml`:
|
|
|
|
```toml
|
|
language-servers = ["harper-ls"]
|
|
```
|
|
|
|
## Formatting
|
|
|
|
Many plain-text email clients _don't_ automatically wrap lines for readers. A
|
|
soft-wrapped email may look completely fine on your end, but be totally
|
|
unreadable for your recipient. Therefore, we need a way to _hard-wrap_ our
|
|
emails before sending them. This ended up being a much bigger challenge than I
|
|
thought it would.
|
|
|
|
My first approach was to use the nifty `wrap` filter that `aerc` ships with by
|
|
adding it to `languages.toml`:
|
|
|
|
```toml
|
|
formatter = { command = "/usr/lib/aerc/filters/wrap", args = ["-w", "74"] }
|
|
```
|
|
|
|
This worked _okay_, but it totally broke the markup at times. Crucially, it
|
|
doesn't respect code blocks or verbatim sections denoted by backticks. If you're
|
|
participating in technical mailing lists, you definitely want these to be
|
|
preserved.
|
|
|
|
Using a regular Markdown formatter introduced another problem: Markup was
|
|
preserved, but not in an email-friendly way. Consider this example:
|
|
|
|
```
|
|
How's it going?
|
|
|
|
Best,
|
|
Daniel
|
|
```
|
|
|
|
A standard Markdown formatter ignores single line breaks and produces this
|
|
output:
|
|
|
|
```
|
|
How's it going?
|
|
|
|
Best, Daniel
|
|
```
|
|
|
|
It similarly mangles signature blocks:
|
|
|
|
```
|
|
--
|
|
Daniel
|
|
Programmer
|
|
email@address.com
|
|
```
|
|
|
|
Becomes:
|
|
|
|
```
|
|
-- Daniel Programmer email@address.com
|
|
```
|
|
|
|
Eventually, I realized that I'd have to write my **own** formatter. I wrote a
|
|
Python script that hard-wraps the input, automatically reflows paragraphs, and
|
|
squashes consecutive paragraph breaks — while preserving the following:
|
|
|
|
- Any long sequence not broken by spaces.
|
|
- Quoted lines (`>` prefixed email quotes).
|
|
- Indented lines.
|
|
- Markdown lists.
|
|
- Markdown code blocks.
|
|
- Signature blocks at end of file.
|
|
- Sign-offs.
|
|
|
|
Sign-offs are preserved by following a simple heuristic. A two-line sequence is
|
|
considered to be a signoff if:
|
|
|
|
- It starts with 1-5 words ending with a comma, followed by
|
|
- 1-5 words that each start with capital letters.
|
|
|
|
This covers signoffs like these:
|
|
|
|
```
|
|
Best,
|
|
Daniel
|
|
|
|
Yours truly,
|
|
John Alfred Smith
|
|
```
|
|
|
|
I provide a number of flags and options, so you can configure the formatter to
|
|
your liking. If you want to use it, `format.py` is available in my
|
|
[mail-utils](https://git.sr.ht/~ficd/mail-utils) repository on sourcehut. To add
|
|
it to your mail workspace just requires changing one line in `languages.toml`:
|
|
|
|
```toml
|
|
formatter = { command = "/path/to/format.py" }
|
|
auto-format = true
|
|
```
|
|
|
|
## Conclusion
|
|
|
|
Hopefully, this guide was helpful in getting you set up with composing your
|
|
emails in Helix. A similar guide for Kakoune is in the works, so check back
|
|
soon!
|