A Guide to MailExtensions

How to build MailExtensions for Thunderbird.

Introduction

MailExtensions are based on the WebExtension technology, which is also used by many web browsers. Such an extension is a simple collection of files which modify Thunderbirds appearance and behavior. It can add user interface elements, alter content, or perform background tasks. MailExtensions are created using standard JavaScript, CSS and HTML. Interaction with Thunderbird itself, like adding UI elements or accessing the users messages or contacts is done through special WebExtension APIs.

Unlike older legacy extensions, MailExtensions access functionality through stable WebExtension APIs and do not have direct access to Thunderbird's internal components or UI elements. Consequently, MailExtensions are less likely to break and do not need frequent and complex updates when Thunderbird's internals change.

The main configuration file of a MailExtension is a file called manifest.json, also referred to as the manifest. Besides defining some of the extension's basic properties like name, description and ID, it also defines how the extension hooks into Thunderbird:

manifest.json
{
"manifest_version": 2,
"name": "Hello World",
"description": "A basic Hello World extension!",
"version": "1.0",
"author": "[Your Name Here]",
"applications": {
"gecko": {
"strict_min_version": "78.0",
"strict_max_version": "78.*"
}
},
"icons": {
"64": "images/icon-64px.png",
"32": "images/icon-32px.png",
"16": "images/icon-16px.png"
},
"background": {
"scripts": [
"background.js"
]
},
"options_ui": {
"page": "options/options.html",
"open_in_tab": false,
"browser_style": true
},
"permissions": [
"storage"
]
}

Manifest keys

A list of all manifest keys supported by Thunderbird can be found in the following document:

The most commonly used manifest keys are explained below.

Basic extension properties

The following manifest keys define basic properties:

  • manifest_version: mandatory key to signal compatibility to Thunderbird, must be set to 2

  • name : mandatory key to set the name of the extension

  • version : mandatory key to define a number that denotes the version of the extension

  • description : a brief description of what the extension does

  • author : should be the name of a person or company representing the extensions developer

The name and the description of the given example are only in English. This MDN article about Localization explains how to use the WebExtension i18n API to localize these keys.

The applications.gecko manifest key defines the following properties:

  • id : The id serves as a unique identifier for the extension, common practice is to use [email protected]. Providing an id is mandatory in order upload an extension to ATN or to be able to install it from an XPI file.

  • strict_min_version: Defines the lowest targeted version of Thunderbird.

  • strict_max_version: Defines the highest targeted version of Thunderbird. It can be set to a specific version or a broader match to limit it to a branch (for example 78.*).

"applications": {
"gecko": {
"strict_min_version": "78.0",
"strict_max_version": "78.*"
}
}

Extension Icons

The icons manifest key tells Thunderbird the location of icons, which should be used to represent the MailExtension. Thunderbird supports basic image types like PNG files, but also SVG files. Thunderbird uses different file icon sizes in different places and allows registering a dedicated file for each size. The MailExtension will use the standard puzzle icon, if no icons have been defined.

"icons": {
"64": "images/icon-64px.png",
"32": "images/icon-32px.png",
"16": "images/icon-16px.png"
}

Background Page

Each MailExtension has a hidden background page. Its main purpose is to load and execute JavaScript files when the MailExtension is loaded. There are two options for its definition:

Defining one or more background scripts

"background": {
"scripts": [
"common.js",
"background.js"
]
}

This will create the background page on-the-fly and load the provided scripts. This is identical to the following background page definition.

Defining a background page

"background": {
"page": "background.html"
}

The defined background page can then load the JavaScript files:

<html lang="en">
<head>
<meta charset="utf-8">
<script src="common.js"></script>
<script src="background.js"></script>
</head>
<body>
</body>
</html>

Options Page

The options_ui manifest key defines the standard MailExtension options page. The defined page will be displayed in the add-on manager.

"options_ui": {
"page": "options/options.html",
"open_in_tab": false,
"browser_style": true
}

The appearance of the options page can be configured as follows:

  • open_in_tab : Open the options page in a tab instead of inline in the add-ons property page.

  • browser_style: Use default browser styles for the options page (recommended).

An inline options page may look as follows:

User Interface Elements

Some UI elements MailExtensions can use are controlled by manifest keys, for example

  • browser_action

  • compose_action

  • message_display_action

Further information about these UI elements can be found in the following document:

Permissions

A core principle of the WebExtension technology is the use of permissions, so users can see which areas of Thunderbird a MailExtension wants to access. Add-on developers can predefine all requested permissions in the permissions manifest key:

"permissions": [
"storage"
]

As permissions allow WebExtensions to use certain APIs, information about supported permissions can be found in the following document:

WebExtension Scripts

Most entry points defined in the extensions manifest allow adding scripts. Most prominent of course the background script(s). Furthermore, each defined HTML page, like the options_ui page allow including scripts via standard HTML <script> tags.

In order to use modern ES6 modules in a loaded script, the type attribute of its script tag must be set to module.

<script type="module" src="background.js"></script>

All these WebExtension scripts have access to:

  • Standard JavaScript methods

  • Web API (if the browser compatibility chart lists Firefox, the API also works in Thunderbird)

  • WebExtension API

A list of all WebExtension APIs supported by Thunderbird can be found in the following document:

Content Scripts

Content scripts (including compose scripts and message display scripts) can only access a small subset of the WebExtension APIs, but they can communicate with background scripts using a messaging system, and thereby indirectly access the WebExtension APIs.

Option Scripts

Access to WebExtension APIs in options pages using options_ui.open_in_tab: false is currently broken. Use getBackgroundPage() to replace the browser object of the options page with the browser object of your background page.

const browser = window.browser.extension.getBackgroundPage().browser;

CloudFile Management Scripts

A script loaded from a CloudFile management_url has access to a limited subset of the WebExtension APIs:

  • cloudFile

  • extension

  • i18n

  • runtime

  • storage

Creating MailExtensions: Examples

Our sample-extensions repository includes a few simple MailExtensions, which showcase different APIs and which will get you started to create your own extension.

We also prepared a step-by-step guide for a small Hello World MailExtension:

Experiment APIs

The currently available WebExtension APIs are not yet sufficient, as some areas of Thunderbird are not accessible through these APIs. We are working on improving the situation.

Currently and for the foreseeable future Thunderbird supports Experiment APIs (a.k.a. Experiments), which are WebExtension APIs that are bundled and shipped together with a MailExtension. They interact directly with Thunderbird's internal APIs and allow add-ons to use additional features not yet available via built-in WebExtension APIs.

These additional APIs can be registered in the manifest.json file by defining an implementation script and a schema file describing the interface:

"experiment_apis": {
"LegacyPrefs": {
"schema": "api/LegacyPrefs/schema.json",
"parent": {
"scopes": ["addon_parent"],
"paths": [["LegacyPrefs"]],
"script": "api/LegacyPrefs/implementation.js",
"events": ["startup"]
}
}
}

If you'd like to learn more about experiments, check out this detailed introduction:

Sharing Experiment APIs

Developers can share and re-use Experiments, if their add-ons have similar needs. Before starting to work on your own Experiment, check if any of the following APIs could already provide the functionality you need. Using them and providing feedback to their developers will help to improve these APIs.

Name

Description

CachingFix

Adding this Experiment API will automatically fix caching issues when the add-on is updated, disabled or uninstalled.

Calendar

💬 📝

Draft for calendar-related APIs in Thunderbird.

ComposeMessageHeaders

Adds missing functionality to add headers to a newly composed message. Aims to add a header object to the compose.ComposeDetails object, so headers can be set via compose.setComposeDetails.

CustomUI

💬

A generic UI extension framework based on iframes registered at fixed extension points.

FileSystem

An API to access files in the users profile folder. Until Mozilla has made a final decision about including the Chrome FileSystem API, this API can be used as an interim solution.

LegacyMenu

Add menu entries to Thunderbird menus currently not accessible using the built-in menus API.

LegacyPrefs

Access Thunderbird system preferences.

NotificationBar

💬 📝

Add Thunderbird notification bars.

Runtime.onDisable

Permit WebExtensions to perform (time-limited) cleanup tasks after the add-on is disabled or uninstalled.

TagService

B 💬

Add/Manage email tags.

TCP

TCP support based on ArrayBuffers (currently client side only).

💬: API has a public announcement post 📝: API has a public interface discussion B : Bugzilla Bug

If you have created an Experiment API which you think could be beneficial to other developers, please tell us about it, so we can include it here.

Proposing APIs to be included in Thunderbird

Creating a good WebExtension API for Thunderbird is not an easy task. New APIs need to be generic and distinct from other APIs. Their interfaces have to be designed with foresight as we should avoid scenarios, where we have to make backward incompatible changes later because we have missed something.

If you want to propose and maybe collaborate on a new API, the following process is suggested:

  1. Announcing the idea and a first outline of the suggested API on discuss.thunderbird.net. An actual implementation is not yet needed, but a general concept of how the API is supposed to work is helpful. This allows the add-on developer community to provide feedback and to make sure the design will cover their needs as well.

  2. Publishing a detailed API description, which can be viewed and commented. Google docs have worked quite well (see here and here), but any platform that allows to collaborate will be sufficient. The goal is to shape out the event, function and type definitions of the API.

  3. Creating a tracking bug on bugzilla, referencing the API description, so the core development team is notified and can comment as well.

  4. Publishing a working implementation, so add-on developers can use it and provide feedback.

  5. Adding a patch to the tracking bug and request review.