Send large files securely from Thunderbird — end-to-end encrypted, GDPR-compliant.
Attachments are automatically uploaded to Retyc before sending, replaced by a secure download link.
- Automatic interception — when you click Send with attachments, the extension offers to upload them to Retyc instead
- End-to-end encryption — files are encrypted client-side before upload using the Retyc SDK
- Passphrase support — required when recipients don't have a Retyc account (minimum 8 characters)
- OIDC Device Flow auth — log in with your Retyc account directly from Thunderbird
- Configurable — transfer expiry and send mode are adjustable in settings
- Clean emails — attachments are removed and replaced by a formatted download link in the message body
- Thunderbird 115 (ESR) or later
- A Retyc account
- Download the latest
retyc-thunderbird-plugin.xpifrom the Releases page - In Thunderbird: Tools → Add-ons → gear icon → Install Add-on From File…
- Select the downloaded
.xpi
npm install
npm run build:devIn Thunderbird: Tools → Add-ons → Debug Add-ons → Load Temporary Add-on… → select dist/manifest.json.
Click the Retyc button in the Thunderbird toolbar (or open Settings) and click Log in with Retyc. A code and URL will appear — open the URL in your browser, enter the code, and authenticate.
Compose an email with one or more attachments and click Send. The extension intercepts the send and opens a confirmation dialog showing:
- The list of attachments and their sizes
- The recipients
If any recipient does not have a Retyc account, enter a passphrase (≥ 8 characters) so they can access the files without an account.
Click Upload & Send — the extension uploads the files, removes the attachments, adds a download link to the message body, and sends the email.
Click Keep attachments to cancel and send normally.
Open Settings from the toolbar popup or via Tools → Add-ons → Retyc → Options:
| Setting | Description | Default |
|---|---|---|
| Transfer expiry | Days before the transfer expires | 7 |
| Send automatically | Send immediately after upload (1-step) vs. review first (2-step) | enabled |
- Node.js 24+
- The
@retyc/sdkpackage is fetched from npm vianpm install— no extra setup required
npm install
npm run build:dev # development build (with source maps)
npm run build # production build
npm run watch # rebuild on file changes
npm run typecheck # TypeScript type-check onlyThe Retyc API URL is baked into the bundle at build time (default: https://api.retyc.com).
To target a local backend, set RETYC_API_URL before building:
RETYC_API_URL=http://localhost:8000 npm run build:devThe correct host permission is automatically written into dist/manifest.json by the webpack build.
src/
background/ # Background script: interception, upload, auth, message router
compose-popup/ # Popup shown from the compose window toolbar button
dialog/ # Upload confirmation dialog (opened as a popup window)
options/ # Settings page
popup/ # Main toolbar popup (auth status, login/logout)
shared/ # Shared types and constants
types/ # Thunderbird MailExtension type declarations
assets/icons/ # Extension icons
dist/ # Webpack build output (gitignored)
The extension uses a background script as the single source of truth. UI pages (popup, dialog, options) communicate with it via browser.runtime.sendMessage.
Send interception flow:
User clicks Send
└─ onBeforeSend fires (background)
├─ No attachments or not logged in → pass through
└─ Attachments + authenticated
├─ Cancel the send
├─ Open dialog popup
│ ├─ User cancels → compose window stays open
│ └─ User confirms (+ optional passphrase)
│ ├─ Passphrase < 8 chars → validation error, retry
│ ├─ API 409 (passphrase required) → back to dialog, retry
│ ├─ Upload files to Retyc (sequentially)
│ ├─ Remove attachments from compose
│ ├─ Append download link to message body
│ └─ Re-send (bypassing interception)
└─ Cleanup on dialog close or tab close
GitHub Actions runs on every push and pull request:
- Type-check (
tsc --noEmit) - Production build (
webpack --mode production) - Lint
- Manifest validation (
web-ext lint) - Node 18, 20 and 22 matrix
On release, a .xpi package is built from the CI artifact and attached to the GitHub release.
Update the version in both files (they must match):
package.json→"version": "X.Y.Z"manifest.json→"version": "X.Y.Z"
npm run package
# → artifacts/retyc-thunderbird-plugin-X.Y.Z.xpinpm run package runs a production webpack build then calls web-ext build, which produces a .xpi directly (a .xpi is a renamed .zip — both formats are valid for Thunderbird).
To test the packaged extension before releasing:
npx web-ext run -t thunderbird --source-dir=distgit tag vX.Y.Z
git push origin vX.Y.ZThe CI package job triggers automatically on release tags and attaches the .xpi to the GitHub release.
Alternatively, create the release manually on GitHub and upload the .xpi from artifacts/.
-
Go to addons.thunderbird.net/developers and log in
-
Submit
artifacts/retyc-thunderbird-plugin-X.Y.Z.xpi -
When prompted for source code, provide the URL of the corresponding GitHub release tag (e.g.
https://github.com/retyc/retyc-thunderbird-plugin/archive/refs/tags/vX.Y.Z.tar.gz) and add the following build instructions in the reviewer notes:Node.js 24+ required. npm ci npm run buildOutput lands in
dist/. The extension is fully self-contained indist/(manifest, JS/CSS/HTML, and assets are all generated there by the build).
ATN reviews the extension and returns a signed .xpi. The validator will flag Thunderbird-specific APIs (compose.onBeforeSend, etc.) as unsupported by Firefox — this is expected and non-blocking for ATN submissions.
Note: Unlike Firefox/AMO, there is no CLI signing API for Thunderbird.
web-ext signtargets AMO only — signing must be done via the ATN web interface.
If you distribute outside ATN, host an updates.json file to enable automatic updates. See the MDN self-hosting guide for the required format.
MIT — © Retyc / TripleStack SAS