Skip to content
Back to skills

Thunderbird Extension

ASecurity

Use when developing Thunderbird MailExtensions - Manifest V2/V3 configuration, messenger.* APIs for accounts, messages, folders and compose, UI actions, message display scripts, Experiment APIs, ATN submission, or migration from legacy extensions

  • 21 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 2, 2026
developmentjavascriptgojavatestingdebugginggitapisecurityperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned October 2, 2026

npx -y skills add CodeAtCode/oss-ai-skills --skill thunderbird-extension --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Thunderbird Extension?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Thunderbird Extension
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/codeatcode-thunderbird-extension/badge)](https://www.skillsdirectory.com/skills/codeatcode-thunderbird-extension)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: thunderbird-extension
description: Use when developing Thunderbird MailExtensions - Manifest V2/V3 configuration, messenger.* APIs for accounts, messages, folders and compose, UI actions, message display scripts, Experiment APIs, ATN submission, or migration from legacy extensions
metadata:
  author: mte90
  version: 2.0.0
  tags:
    - thunderbird
    - mailextension
    - email-extension
    - mozilla
    - atn
    - messenger-api
---

# Thunderbird MailExtension Development

Complete reference for building, testing, and publishing email extensions for Mozilla Thunderbird.

## Overview

Thunderbird extensions use the MailExtension API (based on WebExtensions) with the `messenger.*` namespace. Thunderbird supports both Manifest V2 and V3 since version 128.

**Key Characteristics:**
- Global namespace: `messenger` (Thunderbird-specific) + `browser` (standard WebExtensions)
- Both MV2 and MV3 supported (Thunderbird 128+)
- Thunderbird-specific APIs: `accounts`, `addressBooks`, `compose`, `folders`, `mailTabs`, `messages`, `messageDisplay`
- Submission via ATN (addons.thunderbird.net)

## Version Requirements

| Version | Status | Notes |
|---------|--------|-------|
| 128.x (ESR) | Current | Full MV2 + MV3 support |
| 115.x | Legacy | End of support |
| < 115 | Deprecated | Not recommended |

**Best Practice:** Set `strict_min_version` to "128.0"

## Manifest Structure

### Manifest V3 (Recommended, Thunderbird 128+)

```json
{
  "manifest_version": 3,
  "name": "My Thunderbird Extension",
  "version": "1.0.0",
  "description": "Extension description",
  "author": "Your Name",

  "browser_specific_settings": {
    "gecko": {
      "id": "extension@example.com",
      "strict_min_version": "128.0"
    }
  },

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

  "background": {
    "service_worker": "background.js",
    "type": "module"
  },

  "action": {
    "default_popup": "popup.html",
    "default_title": "My Extension",
    "default_icon": "icons/icon-32.png"
  },

  "permissions": [
    "storage",
    "messagesRead",
    "addressBooks"
  ]
}
```

### Manifest V2 (Still Supported)

```json
{
  "manifest_version": 2,
  "name": "My Thunderbird Extension",
  "version": "1.0.0",
  "author": "Your Name",

  "browser_specific_settings": {
    "gecko": {
      "id": "extension@example.com",
      "strict_min_version": "128.0"
    }
  },

  "background": {
    "scripts": ["background.js"],
    "type": "module"
  },

  "browser_action": {
    "default_popup": "popup.html",
    "default_title": "My Extension"
  },

  "permissions": [
    "storage",
    "messagesRead",
    "addressBooks"
  ]
}
```

### MV2 vs MV3 Key Differences

| Feature | MV2 | MV3 |
|---------|-----|-----|
| Toolbar button | `browser_action` | `action` |
| Background | `background.scripts` | `background.service_worker` |
| Execute script | `tabs.executeScript` | `messenger.scripting.messageDisplay.executeScript` |
| Compose scripts | `composeScripts` | `scripting.compose` |
| Contacts API | `messenger.contacts.*` | `messenger.addressBooks.contacts.*` (vCard only) |

### All Manifest Keys Reference

**Metadata:**
- `name` (required) - Extension name
- `version` (required) - Version string
- `description` - Short description
- `author` - Author name
- `icons` - Extension icons

**Thunderbird-Specific:**
- `browser_specific_settings.gecko.id` - **Required for ATN**
- `browser_specific_settings.gecko.strict_min_version` - Minimum version

**Background & Scripts:**
- `background` - Service worker (MV3) or scripts (MV2)
- `message_display_scripts` (MV2) - Scripts for displayed messages

**UI Components:**
- `action` (MV3) / `browser_action` (MV2) - Main toolbar button
- `compose_action` - Compose window toolbar button
- `message_display_action` - Message view toolbar button

**Permissions:**
- `permissions` - API permissions
- `experiment_apis` - Custom Experiment APIs

**Other:**
- `commands` - Keyboard shortcuts
- `options_ui` - Options page

## UI Actions (Toolbar Buttons)

### Main Toolbar (action / browser_action)

```json
{
  "action": {
    "default_popup": "popup.html",
    "default_title": "My Extension",
    "default_icon": {
      "16": "icons/icon-16.png",
      "32": "icons/icon-32.png"
    }
  }
}
```

```javascript
// Listen for clicks (if no popup)
messenger.action.onClicked.addListener((tab) => {
  console.log("Action clicked");
});

// Update badge
await messenger.action.setBadgeText({ text: "5" });
await messenger.action.setBadgeBackgroundColor({ color: "#ff0000" });

// Update icon
await messenger.action.setIcon({ path: "icons/icon-active.png" });
```

### Compose Window (compose_action)

```json
{
  "compose_action": {
    "default_popup": "compose_popup.html",
    "default_title": "Compose Tool",
    "default_icon": "icons/compose-icon.png"
  }
}
```

```javascript
// Listen for clicks in compose window
messenger.composeAction.onClicked.addListener((tab) => {
  const details = await messenger.compose.getComposeDetails(tab.id);
  console.log("Compose action clicked:", details.subject);
});
```

### Message Display (message_display_action)

```json
{
  "message_display_action": {
    "default_popup": "message_popup.html",
    "default_title": "Message Tool",
    "default_icon": "icons/message-icon.png"
  }
}
```

```javascript
// Listen for clicks on message
messenger.messageDisplayAction.onClicked.addListener(async (tab) => {
  const message = await messenger.messageDisplay.getDisplayedMessage(tab.id);
  console.log("Message action clicked:", message.subject);
});
```

## Message Display Scripts

### MV2 Configuration

```json
{
  "message_display_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["message_content.js"],
      "css": ["message_styles.css"]
    }
  ]
}
```

### MV3 Configuration

```javascript
// In background.js
await messenger.scripting.messageDisplay.executeScript({
  tabId: tabId,
  files: ["message_content.js"]
});
```

### Available APIs in Display Scripts

Limited APIs available:
- `messenger.runtime.connect()`, `messenger.runtime.sendMessage()`
- `messenger.runtime.onConnect`, `messenger.runtime.onMessage`
- `messenger.i18n.getMessage()`, `messenger.i18n.getAcceptLanguages()`
- `messenger.storage.*`

```javascript
// message_content.js
// Send message to background
const response = await messenger.runtime.sendMessage({
  action: "processMessage",
  content: document.body.innerText
});

// Listen for messages from background
messenger.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === "highlight") {
    // Highlight text in message
    document.body.innerHTML = document.body.innerHTML.replace(
      message.text,
      `<mark>${message.text}</mark>`
    );
  }
});
```

## Deep Dives

For detailed reference on specific topics, load these reference files on demand:

- **Messenger APIs** - Complete `messenger.*` API reference (accounts, messages, folders, addressBooks, compose, mailTabs): `./references/messenger-apis.md`
- **Experiment APIs** - Custom Experiment API development guide: `./references/experiment-apis.md`
- **ATN Submission** - Publishing workflow and review criteria: `./references/atn-submission.md`
- **Testing & Migration** - Debugging, testing workflow, and legacy migration: `./references/testing-migration.md`

## Best Practices

### Code Organization

```
my-extension/
├── manifest.json
├── background.js
├── popup.html
├── popup.js
├── compose_popup.html
├── compose_popup.js
├── api/
│   └── myapi/
│       ├── schema.json
│       └── implementation.js
├── icons/
│   ├── icon-16.png
│   ├── icon-32.png
│   └── icon-64.png
├── _locales/
│   ├── en/
│   │   └── messages.json
│   └── it/
│       └── messages.json
└── README.md
```

### Error Handling

```javascript
async function safeAsync(fn) {
  try {
    return await fn();
  } catch (error) {
    console.error("Error:", error);
    return { error: error.message };
  }
}

// Usage
const result = await safeAsync(() => messenger.messages.get(messageId));
if (result.error) {
  console.error("Failed to get message:", result.error);
}
```

### Performance

- Use pagination for large message lists
- Cache frequently accessed data
- Debounce rapid events
- Use `messages.query()` with filters instead of `list()` + filter manually

### Security

- Validate all user input
- Sanitize HTML before display
- Use minimal permissions
- Don't store sensitive data in `storage.local` unencrypted
- Validate message content before processing

## Differences from Firefox WebExtensions

| Feature | Firefox | Thunderbird |
|---------|---------|-------------|
| Namespace | `browser.*` | `messenger.*` (mail) + `browser.*` (common) |
| Context | Web browser | Email client |
| Content scripts | Work on web pages | Only in web tabs, not email content |
| Main action | `browser_action` / `action` | Same + `compose_action`, `message_display_action` |
| Mail APIs | None | `accounts`, `compose`, `messages`, etc. |
| Experiments | Limited | Common for email-specific features |
| Store | AMO | ATN |

## File Structure Template

```
my-thunderbird-extension/
├── manifest.json
├── background.js
├── popup.html
├── popup.js
├── compose_popup.html
├── compose_popup.js
├── message_popup.html
├── message_popup.js
├── message_content.js
├── styles/
│   └── popup.css
├── icons/
│   ├── icon-16.png
│   ├── icon-32.png
│   └── icon-64.png
├── api/
│   └── myapi/
│       ├── schema.json
│       └── implementation.js
├── _locales/
│   ├── en/
│   │   └── messages.json
│   └── it/
│       └── messages.json
└── README.md
```

## Quick Reference

### Essential Permissions

```json
{
  "permissions": [
    "storage",           // Data storage
    "messagesRead",      // Read messages
    "messagesMove",      // Move/copy/delete messages
    "addressBooks",      // Access contacts
    "compose",           // Compose windows
    "accountsRead",      // Read accounts
    "accountsFolders"    // Access folders
  ]
}
```

### Essential APIs

```javascript
// Messages
messenger.messages.list(folderId)
messenger.messages.get(messageId)
messenger.messages.query({ from, unread })
messenger.messages.update(messageId, { read: true })

// Folders
messenger.folders.get(folderId)
messenger.folders.getSubFolders(account)

// Compose
messenger.compose.beginNew({ to, subject, body })
messenger.compose.getComposeDetails(tabId)

// Address Books
messenger.addressBooks.list()
messenger.addressBooks.contacts.create(addressBookId, { vCard })

// Display
messenger.messageDisplay.getDisplayedMessage(tabId)
messenger.messageDisplayAction.onClicked
```

### Workflow Summary

1. **Develop:** Write code, load temporarily
2. **Debug:** Use Debug Add-ons → Inspect
3. **Test:** Test all functionality
4. **Build:** Create .zip with manifest and scripts
5. **Submit:** Upload to ATN
6. **Review:** Respond to reviewer feedback
7. **Publish:** Extension goes live

## References

- [Thunderbird Developer Hub](https://developer.thunderbird.net/add-ons/)
- [WebExtension API Reference](https://webextension-api.thunderbird.net/)
- [Supported APIs](https://developer.thunderbird.net/add-ons/mailextensions/supported-webextension-api)
- [Manifest V3 Guide](https://github.com/thunderbird/webext-docs/blob/beta-mv2/guides/manifestV3.rst)
- [Example Extensions](https://github.com/thunderbird/webext-examples)
- [Experiment Support](https://github.com/thunderbird/webext-support)
- [ATN Developer Hub](https://addons.thunderbird.net/developers/)
- [ATN Review Policy](https://thunderbird.github.io/atn-review-policy/)

Files in this skill

  • SKILL.md11.7 KB
  • references/atn-submission.md2.3 KB
  • references/experiment-apis.md3.5 KB
  • references/messenger-apis.md6.8 KB
  • references/testing-migration.md3.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…