Plain-text mail from Thunderbird (under Linux)

This post was written by eli on June 13, 2014
Posted Under: email,Internet,Software

Introduction

I’ve been annoyed for quite a while by Thunderbird’s strong inclination towards HTML mail. To the extent that if I don’t really, really verify that a mail goes out in plain text, it’s probably going to slip out in HTML. This is bad in particular when sending mails to Linux-related mailing lists. They don’t like it. And the truth is that I’m not very fond of them either, but I usually don’t care.

There’s an add-on for this, Outgoing Message Format, but I run a version of Thunderbird that is too old for that, and trying to fool Thunderbird into installing it by changing the add-on’s version requirement field ended up with an add-on that does nothing.

Upgrading was not an attractive direction: If I’m happy with a tool except for one thing, I’ll fix that thing. Upgrading tends to fix that thing but create a new problem. On a good day.

It turned out to be extremely difficult to convince Thunderbird stopping with that. My notes while trying below.

Note to self: To find the entire hack history, search your “Sent” box for “Thunderbird plain text hacks” in the subject.

Remove the HTML composition capability completely

Ths method makes it impossible for a certain mail identity to compose HTML mails. Go to Preferences > General > Config Editor… and agree to be careful.

mail.identity.id1.compose_html: Set from true to false.

In internal JavaScript code, these preferences are fetched with getPref() commands.

Fixing Thunderbird from within

After wasting a lot of time on this, I reached the conclusion, that the problem was that quite a few components in Thunderbird’s script environment push the HTML format for various reasons. These are apparently ugly hacks that solved a problem for someone in the far past, and remained there, because noone noticed them or understood exactly what they do, possibly including whoever wrote them in the first place.

The solution was a counter-hack. Basically, hide the relevant menu’s IDs from other scripts and set the default to “Plain text”. This requires opening a JAR, making a few fixes in a couple of files, and packing it up again.

So let’s get to it. In a fresh directory,

$ jar xf /usr/lib64/thunderbird-3.0/chrome/messenger.jar

and edit ./content/messenger/messengercompose/messengercompose.xul, in the part saying

<menu id="outputFormatMenu" label="&outputFormatMenu.label;" accesskey="&outputFormatMenu.accesskey;" oncommand="OutputFormatMenuSelect(event.target)">
 <menupopup id="outputFormatMenuPopup">
 <menuitem type="radio" name="output_format" label="&autoFormatCmd.label;" accesskey="&autoFormatCmd.accesskey;" id="format_auto" checked="true"/>
 <menuitem type="radio" name="output_format" label="&plainTextFormatCmd.label;" accesskey="&plainTextFormatCmd.accesskey;" id="format_plain"/>
 <menuitem type="radio" name="output_format" label="&htmlFormatCmd.label;" accesskey="&htmlFormatCmd.accesskey;" id="format_html"/>
 <menuitem type="radio" name="output_format" label="&bothFormatCmd.label;" accesskey="&bothFormatCmd.accesskey;" id="format_both"/>
 </menupopup>
 </menu>

The idea is to hide the elements from any script, except the one that responds to changes in this menu. Also, change the default from “Auto detect” to “plain text”. After the change we have

<menu id="my_outputFormatMenu" label="&outputFormatMenu.label;" accesskey="&outputFormatMenu.accesskey;" oncommand="OutputFormatMenuSelect(event.target)">
 <menupopup id="outputFormatMenuPopup">
 <menuitem type="radio" name="output_format" label="&autoFormatCmd.label;" accesskey="&autoFormatCmd.accesskey;" id="my_format_auto"/>
 <menuitem type="radio" name="output_format" label="&plainTextFormatCmd.label;" accesskey="&plainTextFormatCmd.accesskey;" id="my_format_plain" checked="true"/>
 <menuitem type="radio" name="output_format" label="&htmlFormatCmd.label;" accesskey="&htmlFormatCmd.accesskey;" id="my_format_html"/>
 <menuitem type="radio" name="output_format" label="&bothFormatCmd.label;" accesskey="&bothFormatCmd.accesskey;" id="my_format_both"/>
 </menupopup>
 </menu>

Note the “my_” prefixes on the IDs + that the “checked” attribute has moved.

This leaves a few changes in the only script that should deal with this, ./content/messenger/messengercompose/MsgComposeCommands.js: In

In ComposeStartup(),

document.getElementById("outputFormatMenu").setAttribute("hidden", true);

is replaced with

document.getElementById("my_outputFormatMenu").setAttribute("hidden", true);

and likewise, in OutputFormatMenuSelect()

if (msgCompFields)
 switch (target.getAttribute('id'))
 {
 case "format_auto":  gSendFormat = nsIMsgCompSendFormat.AskUser;     break;
 case "format_plain": gSendFormat = nsIMsgCompSendFormat.PlainText;   break;
 case "format_html":  gSendFormat = nsIMsgCompSendFormat.HTML;        break;
 case "format_both":  gSendFormat = nsIMsgCompSendFormat.Both;        break;
 }

is replaced with

if (msgCompFields)
 switch (target.getAttribute('id'))
 {
 case "my_format_auto":  gSendFormat = nsIMsgCompSendFormat.AskUser;     break;
 case "my_format_plain": gSendFormat = nsIMsgCompSendFormat.PlainText;   break;
 case "my_format_html":  gSendFormat = nsIMsgCompSendFormat.HTML;        break;
 case "my_format_both":  gSendFormat = nsIMsgCompSendFormat.Both;        break;
 }

Finally remove a single line that fiddles with the default (harmless now, but why leave it there…). In the definition of gComposeRecyclingListener, remove this line

document.getElementById("format_auto").setAttribute("checked", "true");

And that’s it.

and then repackage the Jar archive

$ jar cf messenger.jar content

Close Thunderbird, overwrite the original Jar file with the amended one (make a backup copy first, of course) and restart Thunderbird.

I should add, that there are several reasons to be surprised that this is enough. For example, while working on this, I noted that there are several direct calls to OutputFormatMenuSelect(), that attempt to fake a click on one of the HTML-enabling radio buttons. In the aftermath, plain text messages are generated even if this isn’t addressed directly.

Other stuff

During the process of figuring out how to solve this issue, I found a few tricks that may be useful in the future. So here they are

Open all jars you can find

$ find /usr/lib64/thunderbird-3.0/ -iname '*.jar' | while read i ; do ( mkdir "${i##*/}" && cd "${i##*/}" && jar xf "$i" ; ) done

This opens each jar in a directory holding its name (including the .jar suffix)

Set the default HTML format

mail.default_html_action: Set from 3 to 1. Seems not to have a significant effect.

Enabling the dump() command

dump() is used in internal Javascript code to produce debug messages, which are printed to stdout. This requires running Thunderbird from the command line.

In the Config Editor mentioned above, add the boolean browser.dom.window.dump.enabled and set it to true. Otherwise nothing is printed.

Creating stack traces

function DumpTrace()
{
 var err = new Error();

 dump("\nStack trace:\n" + err.stack + "\n\n");
}

The stack trace is pretty ugly, and contains a DumpTrace() too, but it’s good enough to find out why a certain function is called.

 

Add a Comment

required, use real name
required, will not be published
optional, your blog address