Summary
Build a from-scratch, open-source Thunderbird MailExtension that adds Gmail-style snooze to email: hide a message from the inbox now, and have it return automatically at a chosen time. It includes a Gmail-style quick-options menu and a slick, themed calendar date/time picker, triggered by a single-key b shortcut (plus a toolbar button and context menu). It runs fully locally — no external service, no Gmail API.
Why build our own
- Thunderbird has no native snooze.
- Gmail's server-side snooze isn't reachable via IMAP or the Gmail API (we confirmed this), so a Thunderbird key can't trigger real Gmail snooze.
- The polished existing add-on (Snooze Ninja) is paid/closed-source.
- Building our own gives full control over behavior and a UI we can make exactly as slick as we want.
Goals
- Single-key
b opens a snooze menu, just like Gmail.
- Gmail-style quick presets plus a custom date/time picker.
- A slick, smooth, themed UI — matches Thunderbird's theme (light/dark) and the OS accent.
- Reliable local return of snoozed messages that survives Thunderbird restarts and missed alarms.
- Works with a Gmail (IMAP) account; ideally account-agnostic.
Non-goals (v1)
- No server-side/cross-device return. The return happens while Thunderbird is running; if TB was closed at the due time, the message returns on next launch. Document this tradeoff prominently.
- No mobile, no natural-language time parsing.
User experience
Triggering the snooze menu
- Press
b with a message selected/focused in the message list (true single key, like Gmail).
- Also available via a toolbar button (message list + reader) and a right-click "Snooze…" context menu item.
- Acts on the focused message, or on all selected messages if several are selected.
b must not fire while typing in a search box, the quick-filter, a compose window, or any text input (respect focus — mirror tbkeys' stopCallback).
The snooze menu (Gmail-style)
A small popup anchored near the message/toolbar, with rows showing icon + label + the computed return time (right-aligned), hover highlight, and full keyboard nav (↑/↓, Enter, Esc):
- Later today — default +3 hours; if that lands too late, fall back to "This evening" 6:00 PM (configurable).
- Tomorrow — next day at the morning time (default 8:00 AM). e.g. "Tomorrow, 8:00 AM".
- This weekend — upcoming Saturday at morning time (if already the weekend, next Saturday).
- Next week — upcoming Monday at morning time.
- Pick date & time… — opens the calendar picker.
The calendar date/time picker (the slick part)
- Themed month calendar: current month, prev/next navigation, today highlighted, past dates disabled.
- Pick a date → choose a time: preset chips (Morning 8:00 / Afternoon 1:00 / Evening 6:00) plus a custom time input.
- Smooth transitions (month slide, selection pop), rounded corners, soft shadow, clear focus rings, a live preview of the resulting return datetime, and Confirm / Cancel.
- Fully keyboard-drivable and accessible.
Theming & feel
- Match Thunderbird's active theme (light/dark) and OS accent color. Use Thunderbird's in-content theme CSS variables and
prefers-color-scheme; no hard-coded colors.
- Lightweight and instant — vanilla JS + CSS (no heavy framework) for control, load speed, and no layout jank.
Technical design
Add-on type & manifest
- Thunderbird MailExtension. Recommend Manifest V2 for the broadest, most stable API coverage on current Thunderbird (revisit MV3 later).
- Permissions (approx.):
messagesRead, messagesMove, messagesUpdate/messagesModify, accountsRead, folders, storage, alarms, menus.
- Components: background script; message-display action + browser action (toolbar button + popup); menus; options page; and an Experiment API for the single-key
b handler (below).
Message & folder operations (MailExtension APIs)
- Target messages via
mailTabs.getSelectedMessages() / message-display APIs.
- Ensure a "Snoozed" folder exists per account (
folders.query / folders.create); on Gmail this becomes a label.
- Snooze =
messages.move(ids, snoozedFolder) + persist a schedule entry.
- Return =
messages.move(ids, originalFolder) + messages.update(id, {read:false}) (and optionally {flagged:true} / a tag) for visibility.
Scheduling & return
- Persist each snooze in
storage.local: { key, headerMessageId, accountId, originalFolderId, snoozedFolderId, returnAtEpochMs }. Track by headerMessageId (stable across moves), since numeric message ids can change.
- Use
browser.alarms for the next due time; on onAlarm, process everything now due.
- On startup (and periodically), scan for overdue entries and process them → handles the "TB was closed" case.
- Robustness: local-time math with DST awareness; message-not-found (moved/deleted) → graceful skip; guard against double-returns.
Keyboard shortcut (single-key b)
- The WebExtension
commands API generally can't bind a bare letter (needs a modifier). For a true single-key b, use a small Experiment API that installs a keydown listener on the mail:3pane window — exactly the technique tbkeys uses (Mousetrap + a focus-aware stopCallback). Reference: github.com/wshanks/tbkeys (addon/implementation.js, addon/modules/mousetrap.js).
- Make the key configurable (default
b). Ensure it doesn't double-bind if tbkeys is also installed (we intentionally left b unbound in tbkeys).
- Note: shipping an Experiment API means the add-on is fully privileged (not a "lite"/store-listable build) — fine for a self-hosted / sideloaded add-on.
Options / settings
Configurable: morning time, "later today" offset / evening time, weekend day, Snoozed folder name, return behavior (mark unread, flag/tag), the shortcut key, and per-account enable.
Suggested file layout
manifest.json
background.js // scheduler, alarms, orchestration
lib/schedule.js // compute preset datetimes + persistence
lib/messages.js // move / return / ensure-folder / mark helpers
popup/menu.{html,js,css} // Gmail-style quick menu
popup/calendar.{html,js,css} // slick date/time picker
options/options.{html,js,css}
experiment/keys.js + schema.json // single-key `b` handler (tbkeys-style)
icons/
Implementation plan (parallelizable — for batches of agents)
Each task gets its own branch + PR referencing this issue, with frequent commits. After the scaffold, most run in parallel:
Testing plan (real messages, no mocks)
- Manual end-to-end on a real Gmail/IMAP account in Thunderbird:
- Snooze via
b → menu → each preset and a custom date; verify the message leaves the inbox into "Snoozed" and returns at the chosen time, unread.
- Return while TB is running (alarm) and return after restarting TB across the due time (startup catch-up).
- Multiple selected messages; a threaded conversation.
- Timezone/DST sanity; message deleted/moved before return → graceful no-op.
- UI: screenshots of the menu and calendar in light and dark themes; check alignment, contrast, overlap, spacing, and animation smoothness.
- Don't sign off until verified with real examples.
References / code to borrow
- tbkeys (
github.com/wshanks/tbkeys, MIT-style) — single-key handling via Experiment API + Mousetrap + focus-aware stopCallback. Reuse the keyboard technique.
- Open-source Thunderbird snooze add-ons on addons.thunderbird.net (check each listing for a source link — e.g. "Snooze – Remind Me Later", "SnoozeFlow"): reference move/alarm/return mechanics. Do not copy non-open code (Snooze Ninja is paid/closed).
- Thunderbird MailExtension API docs:
messages, folders, alarms, menus, messageDisplayAction, storage.
Open questions / decisions to confirm
- Preset set & default times — confirm: Later today (+3h), Tomorrow 8:00, This weekend Sat 8:00, Next week Mon 8:00. Add "Someday"/"Next month"?
- Return surfacing — unread only, or also flag/star/tag? (True "bump to top" isn't possible for date-sorted IMAP; unread + flag is the realistic signal. Stretch: investigate re-dating/re-injection to bump — risky.)
- Scope — account-agnostic, or Gmail-only for v1?
- Snoozed storage — dedicated "Snoozed" folder/label (recommended). Confirm the name.
- Manifest V2 vs V3.
Constraints
- Repo is public — never commit private info (email addresses, account data, message contents, tokens). Keep all code generic.
- Local-only; document the "Thunderbird must be running for the timed return" tradeoff prominently in the README.
Summary
Build a from-scratch, open-source Thunderbird MailExtension that adds Gmail-style snooze to email: hide a message from the inbox now, and have it return automatically at a chosen time. It includes a Gmail-style quick-options menu and a slick, themed calendar date/time picker, triggered by a single-key
bshortcut (plus a toolbar button and context menu). It runs fully locally — no external service, no Gmail API.Why build our own
Goals
bopens a snooze menu, just like Gmail.Non-goals (v1)
User experience
Triggering the snooze menu
bwith a message selected/focused in the message list (true single key, like Gmail).bmust not fire while typing in a search box, the quick-filter, a compose window, or any text input (respect focus — mirror tbkeys'stopCallback).The snooze menu (Gmail-style)
A small popup anchored near the message/toolbar, with rows showing icon + label + the computed return time (right-aligned), hover highlight, and full keyboard nav (↑/↓, Enter, Esc):
The calendar date/time picker (the slick part)
Theming & feel
prefers-color-scheme; no hard-coded colors.Technical design
Add-on type & manifest
messagesRead,messagesMove,messagesUpdate/messagesModify,accountsRead,folders,storage,alarms,menus.bhandler (below).Message & folder operations (MailExtension APIs)
mailTabs.getSelectedMessages()/ message-display APIs.folders.query/folders.create); on Gmail this becomes a label.messages.move(ids, snoozedFolder)+ persist a schedule entry.messages.move(ids, originalFolder)+messages.update(id, {read:false})(and optionally{flagged:true}/ a tag) for visibility.Scheduling & return
storage.local:{ key, headerMessageId, accountId, originalFolderId, snoozedFolderId, returnAtEpochMs }. Track byheaderMessageId(stable across moves), since numeric message ids can change.browser.alarmsfor the next due time; ononAlarm, process everything now due.Keyboard shortcut (single-key
b)commandsAPI generally can't bind a bare letter (needs a modifier). For a true single-keyb, use a small Experiment API that installs akeydownlistener on themail:3panewindow — exactly the technique tbkeys uses (Mousetrap + a focus-awarestopCallback). Reference:github.com/wshanks/tbkeys(addon/implementation.js,addon/modules/mousetrap.js).b). Ensure it doesn't double-bind if tbkeys is also installed (we intentionally leftbunbound in tbkeys).Options / settings
Configurable: morning time, "later today" offset / evening time, weekend day, Snoozed folder name, return behavior (mark unread, flag/tag), the shortcut key, and per-account enable.
Suggested file layout
Implementation plan (parallelizable — for batches of agents)
Each task gets its own branch + PR referencing this issue, with frequent commits. After the scaffold, most run in parallel:
.xpi, load in TB. (blocking)b— Experiment API keydown handler (tbkeys-style), configurable.Testing plan (real messages, no mocks)
b→ menu → each preset and a custom date; verify the message leaves the inbox into "Snoozed" and returns at the chosen time, unread.References / code to borrow
github.com/wshanks/tbkeys, MIT-style) — single-key handling via Experiment API + Mousetrap + focus-awarestopCallback. Reuse the keyboard technique.messages,folders,alarms,menus,messageDisplayAction,storage.Open questions / decisions to confirm
Constraints