Creating HTML emails with mutt

martin f krafft madduck at madduck.net
Fri Oct 25 22:16:25 UTC 2019


Folks,

I need to start sending out `text/html` alternative parts to my 
messages with mutt. However, this is a rabbit hole, so if you're 
afraid of those, stop reading now.

My requirements are, in decreasing order of priority:

1. Compatible with all Gmail, Outlook, Hotmail, Apple Mail, 
   Thunderbird, and whatever else many people are using these 
   days.
2. Markdown processing of `text/plain`
3. `multipart/alternative` result, MIME compliant
4. Attachments
5. Sensible integration with mutt
6. PGP signatures
7. Inline images

and after surveying the field, and spending hours with the solutions 
I found during various web searches, I am writing in to you for some 
feedback, input, guidance, psycological help, and maybe even some 
hugs.

Since I expect (hope) there to be some insights gained from our 
discussion, I am going to keep updating an [online version of this 
text](https://hackmd.io/@madduck/mutt-html-mails).

The main question for me is: when and how is the best way to add 
that HTML part such that messages can be signed, encrypted, and 
attachments are available to all viewers?

# What is the problem I'm trying to solve?

My current solution[^1], which runs as part of the `$sendmail` 
pipeline and thus converts the message as sent by mutt to a message 
with a MIME tree as follows:

```
I  1 <no description>           [multipa/alternativ, 7bit, 111K]
I  2 ├─><no description>        [multipa/signed, 7bit, 110K]
I  3 │ ├─><no description>      [multipa/mixed, 7bit, 109K]
I  4 │ │ ├─><no description>    [text/plain, quoted, utf-8, 0,4K]
A  5 │ │ └─>Brochure.pdf        [applica/pdf, base64, 108K]
I  6 │ └─>PGP signature         [applica/pgp-signat, 7bit, 1,1K]
I  7 └─><no description>        [text/html, quoted, utf-8, 0,7K]
```

[^1]: I implemented something similar to 
[muttdown](https://github.com/Roguelazer/muttdown), which uses the 
same approach to PGP signatures.

This works fine with mutt, obviously, and Gmail also seems to be 
okay with it, but **Thunderbird doesn't give access to the 
attachments**, and in a way that makes sense, because I am 
advertising the `text/html` part that contains no attachments as a 
better alternative (better because later in the tree, cf. [RFC 
1341](https://www.w3.`org/Protocols`/rfc1341/7_2_Multipart.html)) to 
the whole `multipart/signed` container.

The reason for that, rather than wrapping the `text/plain` part in a 
`multipart/alternative` container, and slap the `text/html` part into 
there is simply that then the PGP signature would be invalidated.

The signature also gets invalidated, if I moved the attachments out 
like this:

```
multipart/mixed
├─>multipart/alternative
│  ├─>multipart/signed
│  │  ├─>text/plain
│  │  └─>application/pgp-signature
│  └─>text/html
└─>application/pdf
```

So in order to make the `text/html` part a true alternative, it needs 
to be converted into a `multipart/mixed` part encompassing the 
`text/html`, as well as the attachment. But given that MIME doesn't 
have pointers or "symlinks", allowing me to reference other parts of 
the tree, the only way to do this from here on (without rethinking 
how I'm approaching this, more on that below) would be to duplicate 
the attachments into a `multipart/mixed` part wrapping the `text/html` 
alternative. And that'd be a terrible waste of resources, and would 
hit max-size limits on SMTP transactions a lot more often.

# What are some other solutions you've considered?

## Converting text to HTML prior to sending

There are plenty of solutions that filter the `text/plain` part once 
created in mutt, and turn it into HTML, replacing the `text/plain` 
part with a `text/html` part. This is not good enough, because I 
often remember something to change at the very last minute, and I 
also don't want to keep just-HTML mails in my sent-mail, because I 
often use commands like `resend-message`, which would then fire up 
Vim on the `text/html` content in my setup.

## Not signing/encrypting messages

If I do not sign messages, my tool does the right thing. However, 
this comes with the price tag that I no longer get to sign my 
messages, which I've done pretty consistently for 25 years. This is 
not really an option.

Obviously, encrypting messages in mutt also won't work, because then 
the Markdown processor cannot actually obtain the `text/plain` part.

## Signing/encrypting messages *after* post-processing

Conceivably, I could convert a `multipart/alternative` into a signed 
or encrypted message *after* my script processes the `text/plain` 
part and adds the `text/html` alternative.

It's even conceivable that I use mutt's `pgp_sign_command` not to 
sign, but instead add metadata that I can use later in the pipe to 
do the actual PGP operation non-interactively, but I suspect that 
this will get messy very quickly.

# What does the ideal solution look like?

It would of course be ideal if mutt gave me a means to post-process 
an entire message *after* writing it to the `$record` folder, and 
*before* it invokes the interactive PGP stuff on it. This probably 
won't be terribly hard to implement, but I haven't even looked at 
the source code yet.

A central question is whether mutt should save the 
`multipart/alternative` message, i.e. including the `text/html` part 
to the sent folder (`$record`), or whether the auto-generated 
`text/html` part should only be added to the outgoing message. This 
probably needs to be made configurable, as some people will want it 
one way, and others another.

On this note, however, I noticed that mutt already has `$fcc_store`, 
and if that is unset, then mutt is already doing different things 
for the messages it stores to the `$record` folder, and the messages 
it sends, because while the messages sent include attachments in the 
`multipart/signed` container, the locally-recorded messages are 
signed, but do not contain the attachments, and so they must 
actually get signed separately.

To me, this suggests that mutt forks message processing, at least if 
`$fcc_store` is unset (and maybe even if it's set), which is good 
because now the aforementioned message post-processor can either be 
invoked before the fork, to keep a record of the 
`multipart/alternative` message, or after the fork and only in the 
branch handling the outgoing message (not the locally saved one).

If we keep a local copy of the `multipart/alternative` messages, 
then mutt needs to also learn how to handle such messages in the 
contact of e.g. `resend-message`, because currently, invoking that 
command on a `multipart/alternative` message will result in the 
MIME-encoded contents of the entire container being loaded in the 
editor, i.e.

```
--b2_50d94a6352b6c4c7225dabd5881a79d4
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

foo

--b2_50d94a6352b6c4c7225dabd5881a79d4
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 8bit

<p>foo</p>
--b2_50d94a6352b6c4c7225dabd5881a79d4
```

and that's not very useful, but could probably be addressed by 
dispensing with the `text/html` part, if mutt is configured to 
auto-generate it during sending anyway.

I'm looking forward to your thoughts on all this. Maybe I'm totally 
overthinking this. In any case, given how email has changed in the 
last 20 years, and how `text/plain` messages are causing display 
issues across different device types (e.g. they are not 
"responsive"), maybe it's time that the least sucky of all mail 
clients gets a little less sucky about generating messages that are 
increasingly being read on mobile devices, or by users who think 
that bold face and images were a feature of SMTP all along.

Best regards,

-- 
@martinkrafft | https://riot.im/app/#/room/#madduck:madduck.net
 
"you grabbed my hand and we fell into it,
 like a daydream - or a fever."
                                      -- godspeed you black emperor!
 
spamtraps: madduck.bogus at madduck.net
-------------- next part --------------
A non-text attachment was scrubbed...
Name: digital_signature_gpg.asc
Type: application/pgp-signature
Size: 1118 bytes
Desc: Digital GPG signature (see http://martin-krafft.net/gpg/sig-policy/999bbcc4/current)
URL: <http://lists.mutt.org/pipermail/mutt-users/attachments/20191026/edd0d6c3/attachment.asc>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mutt.org/pipermail/mutt-users/attachments/20191026/edd0d6c3/attachment.html>


More information about the Mutt-users mailing list