Executing JS Code when receiving an Email with a specific header set

I spent the last two days figuring out exactly how the Thunderbird new email notifications work. My goal was to listen in new Emails for a specific header and then run a specific task. Before I go into details a general note on this first. Please be careful when doing this and be even more careful when passing that header value to your code. The code processing the new mail is privileged and the header value should be treated as unsafe. In the best case this could cause a DoS type attack on your extension, in the worst case attackers could use it to control the user’s Thunderbird.

When I started on this I though it would be easy, a matter of hours. I started with a simple message filter listener, which is what I found on the internet first:


const CUSTOM_HEADER_NAME = "x-my-custom-header";

let listener = {
  QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIMsgFolderListener]),
  msgsClassified: function(aMsgs, aJunkProcessed, aTraitProcessed) {
    for each (let msg in fixIterator(aMsgs.enumerate(), Components.interfaces.nsIMsgDBHdr))) {
      if (msg.getProperty(CUSTOM_HEADER_NAME)) {
        // do something
  // other nsIMsgFolderListener methods ommitted for brevity

function setupListener(listener) {
  const mfn = Components.interfaces.nsIMsgFolderNotificationService;
  MailServices.mfn.addListener(listener, mfn.msgsClassified);

The problem that took me a while to figure out is that the “do something” block is never called. Until I found the actual soltuion, I tried different things like using a pure nsIFolderListener or creating a temporary message filter that takes care. I was convinced that the header values were just not parsed into the nsIMsgDBHdr yet. The reason for this was a very misleading comment in the nsIMsgDBHdr interface. But without some extra code, x-my-custom-header is never added to the properties of the nsIMsgDBHdr. This is done on purpose to keep the database small.

To make it work, we just need to set an extra pref:

let customHeaders = Services.prefs.getCharPref("mailnews.customDBHeaders").split(" ");
if (customHeaders.indexOf(CUSTOM_HEADER_NAME) < 0) {
  Services.prefs.setCharPref("mailnews.customDBHeaders", customHeaders.join(" ").trim());

I hope this saves you a few hours of digging. I certainly would have hoped to find a guide like this, but then again maybe I was looking at the wrong place with the wrong terms.


2 thoughts on “Executing JS Code when receiving an Email with a specific header set

  1. Thanks, though I think there’s an error in the line:
    Services.prefs.setCharPref(“mailnews.customDBHeaderscucustomHeaders.join(” “).trim());

    Extra ” is not closing.
    Maby it should be: Services.prefs.setCharPref(“mailnews.customDBHeaderscucustomHeaders”).join(” “).trim();

    • There seems to be a formatting issue with your comment, I’m not sure where the error is. If you mean this line:

      Services.prefs.setCharPref("mailnews.customDBHeaders", customHeaders.join(" ").trim());

      I believe it is correct. You want to join the customHeaders array with a space delimiter, but that might contain extra spaces if some of the array elements are existing but zero length strings. Therefore it is trimmed, and the value is set as a char pref.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s