Binding a key to “move message to specific folder” in Thunderbird


2021-11-25T19:44:59+01:00
Thunderbird

It shouldn’t be that hard, right? I mean, even Outlook does it, that’s where I got the habit from.

But browsing the preferences, there doesn’t appear to be anything dedicated to binding keyboard shortcuts. So it looks like we’re going to have to install some extension.

I settled for tbkeys-lite. Mostly because that’s what the interwebz said, and more specifically because Keyconfig seems discontinued.

Ok, so I installed the addon, now to configure it.

It explicitly mentions ease-of-use as a non-goal, which is a tradeoff I’m very willing to accept if it indeed does what I came for.

The default configuration comes with a JSO of some sample-yet-useful bindings:

{
    "j": "cmd:cmd_nextMsg",
    "k": "cmd:cmd_previousMsg",
    "o": "cmd:cmd_openMessage",
    "f": "cmd:cmd_forward",
    "#": "cmd:cmd_delete",
    "r": "cmd:cmd_reply",
    "a": "cmd:cmd_replyall",
    "x": "cmd:cmd_archive",
    "c": "func:MsgNewMessage",
    "u": "tbkeys:closeMessageAndRefresh"
}

Straightforward enough.

I want to bind Control-Shift-1.

The precise keybinding syntax is deferred from the tbkeys-lite documentation to the Mousetrap documentation.

The appropriate incantation would be "ctrl+shift+1".

Now to find the internal command to move to my folder. The tbkeys-lite documentation links to a big XML1 directly within the Thunderbird tree in Mozilla’s source control. Quite a few commands available, but not the one I want. The closest match is cmd_moveToFolderAgain: precisely the one I’m trying to make redundant.

Let’s see. tbkeys-lite supports a few different command syntaxes, one of them could be the right choice.

It’s not “Simple command”, because I couldn’t find it in the list. It’s not “Simple function call”: before even browsing the list of functions defined on the Thunderbird window object, it would obviously need an argument, my destination folder, and the syntax explicitly forbids that. It’s not “Custom function call” because, as the description says, there’s only one of those available and it doesn’t do that. It’s not “Unset binding”.

So it’s “Eval”. Which isn’t available in tbkeys-lite, I’ll have to install tbkeys proper.2

All that’s left is figure out the Javascript to perform the call. “All that’s left.” Famous last words.

The first section of the tbkeys-lite documentation had a link to an old page about Keyconfig. Which does have the function I want, properly classified as a “Built-in function with parameters” defined on the “Main window”. It’s named MsgMoveMessage.

It’s declared to take a “Folder URI in quotes” as a parameter. With a helpful link to another Mozillazine page with the folder URI syntaxes. Defining the schemes for local folders, POP3, IMAP and News.

Of course, none of them work for me. This account is using Owl for Exchange. Possibly it defines its own scheme?

By scouring my prefs.js file I find a few examples of its syntax.

user_pref("mail.identity.id5.archive_folder",
          "owl://login%40example.com@outlook.office365.com/Archives");

I copy-paste it to tbkeys’s configuration and update the folder, not forgetting to urlencode the space within. I select a message, press Ctrl-Shift-1, and…

Nothing happens.

The console does have a hint, though:

Uncaught ReferenceError: MsgMoveMessage is not defined

There are a few sample commands to use as bindings in the tbkeys docs, they all prefix with window., perhaps that works here as well?

Uncaught Exception { name: "NS_ERROR_XPC_BAD_CONVERT_JS", message: "Could not convert Javascript argument arg 1 [nsIMsgDBVies.doCommandWithFolder]", result:…

Yikes! Yet it’s progress.

So somehow the MsgMoveMessage, contrary to the outdated information that described the Keyconfig commands, doesn’t look like it takes a Javascript string containing a mailbox URI.

But what else could it take?

After a bit of combined source-diving and web-searching3, I finally spell out the following:

"ctrl+shift+1":
  "Components.utils.import('resource:///modules/MailUtils.jsm');
   window.MsgMoveMessage(
     MailUtils.getExistingFolder(
       'owl://login%40example.com@outlook.office365.com/My%20Folder'
     )
   )",

And it works! Whew.

Importing MailUtils once per call is a bit redundant, so if you know of a cleaner way to do this, please let me know. It’s really not needed at each call — I tried — but it does need to be done at least once and I know of no better place to ensure that.

Anyway, that took much longer than I initially expected for such a simple task. I’m putting it out there in the open in the hope it’ll spare someone some time eventually.


  1. It’s advertised as XHTML. But it’s really XUL, right?↩︎

  2. And not tell you how. Because being a non-trivial install appears to be part of the point of its existence.↩︎

  3. And I’m simplifying.↩︎