Reply with Attachments is a Thunderbird add‑on that automatically includes the original attachments when you reply.
What it does: When you reply to an email, it finds the original message’s attachments and adds them to your reply automatically. Optionally, a small confirmation dialog can ask before adding. If files are excluded by your blacklist, a short warning lists them (enabled by default).
Is it safe? Yes — it runs locally and uses a minimal set of permissions only to read original attachments and add them to your reply. See Permissions: https://bitranox.github.io/Thunderbird-Reply-with-Attachments/docs/permissions
- Ask before adding attachments (optional). Choose the default answer (Yes/No) for quick keyboard entry.
- Blacklist (glob patterns) to skip files automatically, case‑insensitive filename matching.
- Warn if attachments are excluded by blacklist (default: ON). Shows a small, accessible modal listing the excluded files and the matching pattern(s). Works even if all candidates are excluded.
- Include inline pictures (default: ON). Embedded images are restored directly in the reply body as base64 data URIs, preserving the original inline layout. Disable in Options to skip inline images entirely.
See Configuration for details and examples.
- Get the latest release: https://github.com/bitranox/Thunderbird-Reply-with-Attachments/releases/tag/v2.0.0
- Then follow the Quickstart guide below.
Quickstart
- Install from Thunderbird Add‑ons, then reply to a message with attachments — originals will be added automatically or after a quick confirmation (toggle in Options).
- Read the Quickstart guide: https://bitranox.github.io/Thunderbird-Reply-with-Attachments/docs/quickstart
CI & Coverage
- Tests run in GitHub Actions on push/PR with coverage thresholds (85% lines/functions/branches/statements).
- Coverage HTML is uploaded as a build artifact in the CI run (Actions → latest run → Artifacts → coverage-html).
Release process
- Bump versions in
sources/manifest_ATN.jsonandsources/manifest_LOCAL.json. - Tag the commit as
vX.Y.Z. Pushing the tag triggers packaging and a GitHub Release with zips.
If you like this add‑on, please consider supporting it:
The extension follows a layered clean architecture to keep business logic testable and framework‑independent:
Domain → Application → Adapters → Composition → Background
| Layer | Directory | Responsibility |
|---|---|---|
| Domain | sources/app/domain/ |
Pure functions: attachment filtering (includeStrict, includeRelaxed), blacklist matching, content‑type helpers. No side effects. |
| Application | sources/app/application/ |
Use‑cases: processReplyAttachments orchestrates fetch → filter → attach. Depends on domain; receives adapters via injection. |
| Adapters | sources/app/adapters/ |
Thunderbird WebExtension API wrappers (messages.listAttachments, compose.addAttachment, etc.). Isolates platform calls behind a consistent interface. |
| Composition | sources/app/composition.js |
Wires adapters into use‑cases, manages reactive settings (storage.onChanged), registers event listeners. |
| Background | sources/background.js |
Entry point. Bootstraps install/migration, loads composition, seeds defaults. |
Event pipeline (reply flow):
compose.onStateChanged
→ handleComposeStateChanged (resolve tab, fetch details)
→ ensureWrapper (wait for settings, rebuild use‑case)
→ ensure (processReplyAttachments: fetch → filter → attach)
Each compose tab is processed at most once per reply via session‑based idempotency (browser sessions API + in‑memory map).
Key design decisions:
- Session markers prevent duplicate processing across restarts.
- Reactive settings — options changes propagate via
storage.onChangedwithout restart. - Confirm fallback chain — scripting.compose → content script → messaging, with graceful degradation.
- Translate homepage/navbar/footer UI strings (requires
OPENAI_API_KEY):make translation_web_index_page(all locales, skipen)make translation_web_index_page OPTS="--locales de,fr --force"to limit/overwrite
- Translate docs pages: see
website/docs/development.md(Translate the Website).
