v2026.3.1
Highlights
- Views can now match on multiple sender and recipient addresses, and support regular expressions for text, from, to and subject.
- Settings are reorganized into clearer groups with a search box that finds individual settings, not just categories.
- New offline indicator in the status bar. When there is no connection, sync and the raw-source viewer say "No internet connection" instead of confusing credential or host errors.
- Unified Inbox and the built-in view names (Inbox, Flagged, Drafts, Sent, and more) are now fully localized.
- Optional fullscreen empty-state background image for the reading pane, off by default.
- New "This email" action to load remote content for a single message, remembered across syncs.
- Polish language support.
Changes
feat: add Polish (pl) locale -
@TRC-Loop in #153
Closes #140.
Adds a Polish (pl) locale.
Changes
- New
frontend/src/lib/locales/pl.tstranslating every key fromen.ts. Key set is at exact parity with en.ts (verified by diff); placeholder tokens ({count}, {who}, {when}, {version}, {n}, {field}, {folder}, {size}, {mailbox}, {author}, {detail}) are preserved verbatim, and technical terms (IMAP, SMTP, OAuth, Gravatar, BIMI, PGP, SPF/DKIM/DMARC, MCP, TLS/SSL/STARTTLS, Markdown, HTML, Vim, proxy) are left untranslated. - Registered
plin the i18n loader/selector (Localetype,localesarray,localeNames-> "Polski", dynamic import map), so it is selectable in Settings. - Extended the Go-side locale tables so Polish users also get native strings: built-in locales set (
bind_locales.go), new-mail notifications (notify.go), and the native menu bar (menu_i18n.go). - No em-dashes in any string.
Verification
- pl.ts key set diffs clean against en.ts.
- go build, go test (internal/desktop), svelte-check and pnpm build all pass.
Note: this is a complete first-pass translation; a native-speaker review pass is welcome as a follow-up.
feat: fullscreen empty-state background toggle -
@TRC-Loop in #152
Closes #148.
Adds an option to show the empty-state image as a full-screen background of the reading pane, instead of the small centered mark.
Changes
- New
emptyStateFullscreenboolean preference, off by default. - When on (and an empty-state image is set), the reading pane renders that image as a full-bleed
coverbackground when no message is open. Otherwise the existing small, faded, centered mark is unchanged. - Toggle added in Settings next to the empty-state image picker; it is disabled until an image is chosen.
- Wired through backend setting (
empty_state_fullscreen), UIPrefsDTO, prefs store + setter, api key, types, and generated bindings. - i18n keys added to all five locales (en/de/fr/es/nl).
Verification
- go build, svelte-check, and pnpm build all clean.
feat: group and rebalance settings categories with per-setting search -
@TRC-Loop in #151
Closes #130.
The settings panel had ~20 flat categories with a badly overloaded Appearance section and several near-empty ones. This groups and rebalances them and adds real per-setting search. Every existing setting is preserved, only relocated.
Categories: 24 → 16, grouped under 6 headings
- Appearance now holds theming only: theme/schedule, accent, density, corners, interface scale, reduce motion, empty-state image.
- Menu bar (new): the whole macOS menu-bar cluster pulled out of Appearance.
- Reading & display = Display + Panes + all three font pickers (body/UI/mono moved out of Appearance).
- Message list = List + Sidebar + Avatars.
- Composing & sending = Composing + Sending.
- Privacy & network = Privacy + Network.
- Accounts = Mailboxes + Contacts.
- Backup & integrations = External + Import/Export.
- Sync & power = Power + Offline/download.
- Unchanged: Themes, Language, Signatures, Notifications, Gestures, Shortcuts, About.
Nav groups: Appearance / Mail / Privacy / Accounts / Advanced / About. Merged sub-groups get a labeled divider so nothing reads as a jumble.
Per-setting search
Typing filters the nav and shows a flat results list of individual settings by their own label (e.g. proxy, gravatar, vim, undo send, swipe, backup), each tagged with the category it lives in; clicking jumps straight there.
Spacing and space
- Hints now hug the control they describe with a clear gap below, so they read as part of that setting instead of floating between two.
- Content column widened 560 to 720px.
i18n / verification
- New keys (groups, per-category keywords, new category labels, Menu bar) added to all five locales (en/de/fr/es/nl), files at parity.
- Every category key maps 1:1 to a render block; no setting removed.
- svelte-check clean, pnpm build clean.
feat: multi-address chips and regex matching in views -
@TRC-Loop in #150
Closes #149.
Saved views can now filter with multiple sender/recipient addresses and match content with regular expressions.
Changes
- Multi-address chips for From / To. The single-line
fromandtoinputs are now chip inputs: type an address, press Enter/comma/semicolon (or blur) to add it, remove with backspace or the x. A message matches the field when it matches any chip (OR within the field); fields still AND with each other. - Regex toggle. A per-view "Use regular expressions" option treats the text/from/to/subject criteria as regular expressions instead of plain substrings. Invalid patterns are rejected on save; a view whose regex fails to compile at run time matches nothing rather than breaking the sidebar.
Implementation
- Plain single-address views keep the existing full-text index path (unchanged behavior/perf). Regex or multi-address views take a scan-and-filter path: read the newest messages in scope (capped by
maxViewScan), then match in Go. Matches stay capped atmaxViewMatches. - Storage: new
use_regexcolumn (migration 0012);query_from/query_tonow hold a newline-separated address list. Existing single-address views load as one-item lists, so nothing breaks on upgrade. - Plain matching is case-insensitive substring; regex is matched as written (use
(?i)for case-insensitive). - i18n keys added to all five locales. Generated Wails bindings updated for the new DTO shape.
Tests
internal/desktop/bind_views_test.go: multi-address OR, case-insensitive plain match, regex alternation, invalid-regex rejection, and field ANDing.- Full
go test ./internal/...,svelte-check, andpnpm buildpass.
feat: persistent per-message remote content allow -
@TRC-Loop in #154
Closes #136.
Adds a persistent per-message remote-content allow, so a newsletter or receipt you reopen often can render remote images every time without trusting the whole sender or domain.
Approach
Chose option 1 from the issue: a fourth banner action, This email, alongside "Load once" / "This sender" / "This domain". It is non-modal and does not change what "Load once" does (which stays ephemeral).
Changes
- Backend
AllowRemoteForMessage(messageID)records the message in a newremote_allow_messagessetting. It is keyed by the RFC Message-ID header (lowercased/trimmed) so the allow survives re-sync, expunge and a changed local row id; when a message has no Message-ID it falls back tolocal:<row id>. GetMessagenow renders remote content when the message is individually allowed:remoteAutoAllow(from) || remoteMessageAllowed(m). The existing global / sender / domain paths are untouched, so privacy defaults (blocked by default) are unchanged and this stays an explicit per-message opt-in.- Frontend: new banner button wired to
allowRemoteForMessage; on click it persists and renders remote content immediately. New i18n keys added to all five locales (en/de/fr/es/nl). No em-dashes. - Generated Wails bindings + api wrapper updated for the new method.
Tests / verification
internal/desktop/bind_images_test.go: Message-ID keying and local fallback.- go build, go test (internal/desktop), svelte-check and pnpm build all pass.
Full Changelog: v2026.3...v2026.3.1