Expanding a conversation in the message list (row click, expand chevron,
or the `x` shortcut) and clicking a row in a Pro folder tab marked the
messages read straight away. They ignored "Mark as read: Never" and any
delay, which the reading pane and the conversation view follow.
Route them through one helper, scheduleAutoMarkAsRead: -1 never marks,
0 marks at once, any other value marks after that many milliseconds and
returns a cancel function.
- New store action autoMarkExpandedThreadAsRead keeps one pending timer
per thread key. Collapsing the thread, or collapsing all threads, drops
it. Both expansion paths (EmailList and the `x` handler in MailApp) use
it.
- MailApp's handleEmailSelect drops the pending mark of every expanded
thread other than the one the newly opened message belongs to, through
cancelAutoMarkThreadAsRead. Moving on with `j`/`k` or a click no longer
lets the delayed mark land on a conversation the user has left. The
thread stays expanded.
- ProFolderTabBody schedules the row mark through the helper and drops a
pending one when another row is opened or the tab unmounts.
A new feature gate, archiveActionEnabled (default on), lets the admin turn the
Archive action off for installations that archive mail elsewhere, such as a
mail gateway. With it off, Bulwark offers no Archive anywhere: the viewer's
button and its overflow entry, the context menu for one or several messages,
Mountain View's selection bar, the hover and swipe actions, the E shortcut and
its help row, archiving after an export, and the archive mode setting (also in
the settings search). With it off nothing creates an Archive folder:
ensureArchiveMailbox returns null. Existing Archive folders stay ordinary
folders, moving mail into them by hand still works, and the plugin API is
unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream renamed the store's selection from bare email ids to
account-scoped selectedEmailKeys, and a bare id can name a different
message in another account. Route the batch forward-as-attachment
handler through resolveSelectedEmails like the other batch actions:
it matches keys against the loaded rows and expanded thread members,
and the scheduled view it used to special-case offers no selection.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Multi-select emails in the list, right-click, and pick "Forward as
attachments" to open one composer carrying every selected message as
its own message/rfc822 (.eml) attachment - the batch sibling of the
existing single-message action.
- lib/forward-as-attachment.ts: buildBatchForwardAsAttachmentPayload
builds one payload from many emails. The subject is count-based
(there is no single original subject), with the count localized via
an injected label so the subject never claims more attachments than
the composer carries. Emails without a blobId are skipped; null when
none has one, matching the single flow's silent no-op.
- mail-app.tsx: handleBatchForwardAsAttachment resolves the selection
through useEmailStore.getState() (fresh state, list-ordered
attachments, stale ids drop out), runs the plugin transform and veto
hooks per email - one veto cancels the whole compose - and opens the
composer with the attachments seeded via replyTo. Clears the
selection only on success.
- email-context-menu.tsx / email-list.tsx: new batch menu item shown
when the right-clicked email belongs to a multi-selection; hidden in
the scheduled view like the single item.
- locales: context_menu.forward_as_attachments and
email_composer.forward_batch_count in all 27 locales.
Co-Authored-By: Claude Code <noreply@anthropic.com>