net.thunderbird URLs

In some circumstances you may need a way to talk to Thunderbird from a web browser, and the best way to do that is with a URL. A URL can be linked on web pages for the user to click on, or an HTTP request can redirect to a URL.

Thunderbird provides the custom URL protocol net.thunderbird: for this purpose. Thunderbird will handle URLs of the form net.thunderbird://component/arguments where component is the name of a component registered in the category manager. The URL is passed to the observe function on the component.

OS Registration

Thunderbird must be pre-registered with the operating system as the handler of net.thunderbird URLs. You can check if it is, and make it so, by running this code:

const shellService = Cc["@mozilla.org/mail/shell-service;1"].getService(Ci.nsIShellService);

// Check if this install of Thunderbird is the handler of net.thunderbird URLs.
const isDefault = shellService.isDefaultClient(false, Ci.nsIShellService.NET_THUNDERBIRD);

if (!isDefault) {
  // Set this install of Thunderbird to be the handler of net.thunderbird URLs.
  // You shouldn't do this without the user's permission.
  shellService.setDefaultClient(false, Ci.nsIShellService.NET_THUNDERBIRD);
}

(Even if Thunderbird is the handler, if there are multiple profiles, there’s no guarantee which profile will be used.)

Alternatively, there is UI for this check in the Settings tab, under “System Integration”.

Adding a component

Pick a name

It should uniquely identify what the URL does and wouldn’t ever be used by another part of Thunderbird. Also it’s the host part of a URL, so stick to lower-case letters, numbers, and maybe - or . if you really must.

Design your URL

It will be net.thunderbird://, plus the name of your component, plus / and any extra information you want to include. Extra information can be appended directly to the URL path, e.g. net.thunderbird://mycomponent/foo/bar and/or using search parameters, e.g. net.thunderbird://mycomponent/?foo=bar. What you do will depend on your needs. You may need to consider:

  • URL encoding characters

  • versioning, if your URL could be used with past or future versions of Thunderbird

  • not including sensitive information

Warning

Anybody could construct a URL and put it on a web page, so data we get from one should never be naïvely trusted. Don’t add a component that creates or deletes items, or sends any kind of request, without user confirmation.

Write your code

You’ll need an object that implements nsIObserver, which will be called when Thunderbird is given a URL to load:

export class MyComponent {
  QueryInterface = ChromeUtils.generateQI(["nsIObserver"]);

  observe(subject, topic, data) {
    if (topic == "net-thunderbird-url") {
      // `data` contains the URL.
    }
  }
}

If necessary this code should deconstruct the URL (URL and URLSearchParams are your friends here).

Note

There should only ever be a single instance of your component. It will be instantiated with getService and not createInstance.

Register your component

Add it to a components.conf file. For a JS component, this is all you need:

{
    "cid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",  # Use a real UUID. :-)
    "contract_ids": ["@mozilla.org/my-component;1"],
    "esModule": "resource:///modules/MyComponent.sys.mjs",
    "constructor": "MyComponent",
    "categories": {"net-thunderbird-url": "mycomponent"},  # This will be the host part of the URL.
}

Change each line to point to your actual component, obviously. More information about registering XPCOM components.

Rebuild

This may take a little while because adding a component requires a lot of things to be rebuilt.

Try it

You should be good to go. If Thunderbird (your local build) is the default application for mail then clicking on a link in a browser should bring Thunderbird to the front and run your code.

For a simple check, type data:text/html,<a href="net.thunderbird://mycomponent/foo/bar">click me</a> in your browser’s address bar.

Write tests

Please add automated tests for your new component.

To simulate a click on a URL in a browser, call the observe method with the same data it would see in real-world use:

const service = Cc["@mozilla.org/my-component;1"].getService(Ci.nsIObserver);
service.observe(null, "net-thunderbird-url", "net.thunderbird://mycomponent/test");

Document

Add your component to the list below with a description of what it does and give example URLs to illustrate how to use it.

Components

  • replay is a test component which simply records the URL to be checked later on.