How to make a filter for calendar/event/appointment invites in Thunderbird 38.2+

calendaremailemail-filterthunderbirdthunderbird-addon

I would like to tag all incoming mails which include a calendar invite. Then I would like to move them into a different folder.
I tried the method described in this answer, but it doesn't work:
I tried a find a header named "Content-Type" with the content "text/calendar" but it didn't work.

I also tried the addon FiltaQuilla, which failed as well.
I used following code there:

var sHeaderToLookFor = "content-type";
var sContentInHeader = "text/calendar";
var bFoundIt = false;
function msgHdrGetHeaders(aMsgHdr, k) {
    let uri = aMsgHdr.folder.getUriForMsg(aMsgHdr);
    let messageService = MailServices.messenger.messageServiceFromURI(uri);
    MsgHdrToMimeMessage(aMsgHdr, null, function (aMsgHdr, aMimeMsg) { k(aMimeMsg);  }, true, { partsOnDemand: true, examineEncryptedParts:true });
}

msgHdrGetHeaders(message, function (aHeaders) {
    if (aHeaders.has(sHeaderToLookFor)) {
        var pattern = new RegExp(sContentInHeader);
        Application.console.log("InBetween_1");
        if (!bFoundIt)
            bFoundIt= pattern.test(aHeaders.get(sHeaderToLookFor));
        Application.console.log(bFoundIt);
        Application.console.log("InBetween_2");
    }
});

Application.console.log("AtEnd_1");
Application.console.log(bFoundIt);
Application.console.log("AtEnd_2");
bFoundIt;

I had following output on the console after testing the filter on an email with an .ics invite:

AtEnd_1
false
AtEnd_2
InBetween_1
true
InBetween_2

So basically, this filter with JavaScript would work. But it doesn't work because MsgHdrToMimeMessage() will call the callback after the Filter has returned "false" to FiltaQuilla. I would need to make the code wait (use it synchronously instead of asynchronously), but I have no idea of how to do that.

Anyway, I am not really focused in using FiltaQuilla. I would just like to have a solution for my problem.

I use IMAP and I save my emails on my local HD for offline email reading.

There was an older Thunderbird version where FiltaQuilla worked (something like 24.x), and there where even older versions of Thunderbird (like 3.x) where filters on headers worked. But something changed and now I don't know how to filter anymore.

Best Answer

Finally found a solution for that. Below JavaScript code works fine with FiltaQuilla and Thunderbird 38.2.0.

{
    var sHeaderToLookFor = "content-type";
    var sContentInHeader = "text/calendar";

    var hwindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
            .getService(Components.interfaces.nsIAppShellService)
            .hiddenDOMWindow;
    function waitFor(callback, message, timeout, interval, thisObject) {
        timeout = timeout || 5000;
        interval = interval || 100;
        var self = {counter: 0, result: callback.call(thisObject)};
        function wait() {
            self.counter += interval;
            self.result = callback.call(thisObject);
        }
        var timeoutInterval = hwindow.setInterval(wait, interval);
        var thread = Components.classes["@mozilla.org/thread-manager;1"].getService().currentThread;
        while ((self.result != true) && (self.counter < timeout)) {
            thread.processNextEvent(true);
        }
        hwindow.clearInterval(timeoutInterval);
        if (self.counter >= timeout) {
            message = message || arguments.callee.name + ": Timeout exceeded for '" + callback + "'";
            throw new TimeoutError(message);
        }
      return true;
    }

    var bFoundIt = false;
    var called = false;
    function msgHdrGetHeaders(aMsgHdr, k) {
        let uri = aMsgHdr.folder.getUriForMsg(aMsgHdr);
        let messageService = MailServices.messenger.messageServiceFromURI(uri);
        MsgHdrToMimeMessage(aMsgHdr, null,
            function(aMsgHdr, aMimeMsg) {
                try {
                    k(aMimeMsg);
                }
                catch (ex)
                {
                }
                finally {
                    called = true;
                }
            },
            true, { partsOnDemand: true, examineEncryptedParts:true });
    }

    msgHdrGetHeaders(message, function (aHeaders) {
        if (aHeaders.has(sHeaderToLookFor)) {
            var pattern = new RegExp(sContentInHeader);
            // Application.console.log("InBetween_1");
            if (!bFoundIt)
                bFoundIt = pattern.test(aHeaders.get(sHeaderToLookFor));
            Application.console.log(bFoundIt);
            // Application.console.log("InBetween_2");
        }
    });

    waitFor(function () called, "Timeout waiting for message to be parsed");
    // Application.console.log("AtEnd_1");
    Application.console.log(bFoundIt);
    // Application.console.log("AtEnd_2");
    bFoundIt;
}

I used the waitFor() function from https://searchcode.com/codesearch/view/21382111/. That link seems to be the source from the Thunderbird test library (/thunderbird-14.0/comm-release/mail/test/resources/mozmill/mozmill/extension/resource/modules/utils.js)

Anyway, if someone else has a similar problem, where he wants to parse headers of emails on IMAP folders, he can use above code and just change "sHeaderToLookFor" and "sContentInHeader" to his needs.

Related Question