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:
text/plain
multipart/alternative
result, MIME compliantand after surveying the field, and spending hours with the solutions I found during various web searches, I am jotting down some ideas here.
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?
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]
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) 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.
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.
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. See next:
pgp_sign_command
to do the conversionIt is my understanding that the pgp_sign_command
returns just the
signature, which mutt then wraps in a application/pgp-signature
part
and hooks it under the umbrella of a multipart/signed
part, next to
the text/plain
part.
I am pretty sure things will go funky if the pgp_sign_command
returns
HTML, or even a full MIME part, instead of just the signature.
However, it's conceivable that pgp_sign_command
and
pgp_encrypt_command
actually don't be used to output signatures
or encrypted text, but merely to augment the message with control
information, which can then be used during a $sendmail
pipeline
to do the actual crypto operation after the text/html
part was
auto-generated.
Nevertheless, this would mean that messages would be stored locally
in $record
with these metadata, which means mutt will choke trying
to interpret these data as signatures, and also means that we're
storing unencrypted messages, when the user actually chose encryption,
which might be really bad on multiuser systems.
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.
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.
old