Files
RustBox/docs/IMPLEMENTATION_STATUS.md
T
Mateusz Gruszczyński 2932578424
RustBox CI / rustbox (push) Waiting to run
v0.2.31
2026-11-08 16:42:41 +01:00

45 KiB

RustBox 0.2.31 - implementation status

  • Draft saves are realtime-silent: Drafts folder/list updates continue, but saving a draft does not surface as a new-mail notification. This file tracks the 0.2.31 source snapshot. Storage/search scope and outstanding acceptance work are tracked in TODO.md. A feature is only listed as implemented when working code exists in this source tree; partial items are called out explicitly.

0.2.31 touch action sheet

  • On touch screens (hover: none) a long press (450 ms) on a message row opens #context-menu as a bottom sheet: sender/subject header, quick actions (read/unread and flag via the flags endpoint, archive/delete via performBulk on that message with undo), then the desktop context-menu items with drill-down submenus.
  • The sheet uses the theme tokens (--ui-size, --ui-scale-factor, --density-factor, --icon-size, --radius-*), is capped at 560 px on tablets, owns one history entry (Android back closes it) and closes on backdrop tap, drag-down, Escape or any action. Rows are not draggable on touch screens; the hover quick-action overlay is hidden there.
  • Context-menu "Mark read/unread" and "Flag/Unflag" update flags without opening the message.

0.2.30 CalDAV / CardDAV server

  • Optional ([dav] enabled = true): one calendar (VEVENT) and one address book per account under <base_path>/dav/, RFC 6764 .well-known redirects, HTTP Basic auth against IMAP with a login cache and the login brute-force guard.
  • PROPFIND, REPORT (calendar-query with time-range, calendar-multiget, addressbook-query, addressbook-multiget), GET/HEAD, PUT, DELETE, strong ETags with If-Match/If-None-Match, CTag. Not implemented: sync-collection, VTODO, MKCALENDAR/MKCOL, server-side recurrence expansion.
  • Uploaded objects are stored verbatim (dav_data, migration V055) and webmail edits are patched into them per property. Details: docs/CALDAV_CARDDAV.md.

0.2.29 realtime open-thread refresh

  • When realtime reports NewMessages, the currently open message detail is re-fetched and its thread is re-rendered if the user is still viewing the same message.

0.2.28 thread replies and legacy Polish mail decoding

  • Reply composition detects all configured account/identity addresses; replying to an own sent message selects the first non-own recipient and Reply all keeps the remaining external participants.
  • The mailbox toolbar toggles the existing thread_mode preference between a grouped thread list and a flat message list. Thread groups use Message-ID/In-Reply-To/References metadata, can be expanded/collapsed, and the reader follows the same preference.
  • Header/body rendering repairs common Polish mojibake while retaining RFC 2047 charset decoding; cached summaries/details are normalized on output so old cached rows benefit without a schema migration.

0.2.27 mail-list and appearance polish

  • Monochrome changes on a predefined style promote it to a custom copy before applying the change.
  • Wide message rows give the subject more horizontal space and expose its full value in a tooltip.
  • Read/unread, flag and open actions appear to the left on hover without reserving hidden row width.
  • Shift-click popups use a reader-only embedded layout from initial render.

0.2.26 licensing and documentation

  • Licensed under AGPL-3.0-only with an optional commercial license (LICENSE, LICENSING.md, NOTICE.md). The Oxi synchronisation scripts and UPSTREAM_BASE were removed; the About page no longer embeds an Oxi revision.
  • docs/FEATURES.md lists all features with screenshots (docs/screenshots/, generated against a mocked API).
  • Translations are applied to dynamic settings notes after they load.

0.2.25 filters

  • Apply now (POST /api/filters/match, src/routes/filters.rs): the client sends the rule as a JSON tree ({op: allof|anyof, args}, {not}, {test: {kind, match, value, header}}, max depth 12 / 64 tests). The server translates it into two IMAP UID SEARCH criteria — an upper bound (superset) and a lower bound (certainly matching) — and runs them via the new ImapClient::search_uids. Header/subject :contains tests and sizes are exact; address tests (IMAP FROM also matches display names), :is / :matches, non-ASCII values and has-attachment are narrowed from the messages cache with three-valued evaluation; messages that still cannot be decided are counted as uncertain and not touched. At most 20 000 UIDs are returned.
  • The client (91-sieve-apply.js) applies, per message: flags (\Seen, IMAP keywords), labels (bulk tag endpoint), copies, then one move/Trash — via the existing message endpoints, 4 requests at a time with progress. Redirect, discard and set-flags are not applied to existing messages and are listed as skipped in the confirmation.
  • Entry points: Check matches / Apply now in the rule editor (re-check required after the rule changes), Apply now per rule in the rule list (rules using syntax the editor cannot rewrite are refused), the quick filter dialog option, and Always move messages from this sender… in the message context menu.
  • Editor additions: exceptions (allof (<conditions>, not anyof (<exceptions>)), parsed back), conditions to-only, cc-only, size-over / size-under, has-attachment (requires mime), priority-high (X-Priority 1/2 or Importance: high), actions label (addflag "RustBox-<tag id>") and trash, templates, missing-folder creation on save. No schema change.
  • Not done: drag-and-drop reordering of rules (the ↑/↓ buttons remain).

0.2.25 interface fixes

  • Message context menu: grouped into submenus (Forward, Labels, Snooze, Filters, Sender, More); menus are capped at the window height and scroll; scrolling inside a menu does not close it; submenus open on hover, click or →, close with ← / Esc.
  • Predefined-style editing: enabling it copies the style's layout profile into the user's display preferences and the layout then follows those values while the style's palette, tokens and gradients stay active. A colour change asks to create a RustBox custom copy built from the computed palette on screen plus the current layout, and pins theme to the resolved light/dark mode. Changing interface_skin clears preset_scale_unlocked; changing skin_depth while editing re-seeds the layout.
  • data-contrast="soft" no longer defines --line from itself (a CSS custom-property cycle that left it empty).

0.2.24 style gradients and retro styles

  • "Style gradients" (skin_gradients) now works at every style depth. Gradients live only in 59-skin-gradients.css, generated from one table: --grad-backdrop, --grad-appbar, --grad-toolbar, --grad-sidebar, --grad-selected and --grad-primary are painted as background-image layers over the colours chosen by the palette and depth, so translucent defaults work for every style; signature styles override them with opaque gradients and declare matching app-bar / button text colours. The RustBox custom style is excluded. 57-skin-tokens.css no longer contains gradients.
  • Adds Windows XP, Mac OS X Aqua, iOS 6, Windows 7 Aero, Frutiger Aero and BeOS inspired styles, each with palettes, a layout profile, structural tokens and signature gradients.
  • Theme "By time of day" (theme = schedule, theme_light_from / theme_dark_from, migration V054): evaluated in the browser's local time, re-checked every minute.
  • Optional per-account colour (account_color, V054): 3px stripe on the app bar and a dot before the account address. Display preferences are stored per account, so each account keeps its own colour.
  • Custom colours show a live WCAG contrast warning (text/panel, text/background, text/selection 4.5:1; secondary text and accent 3:1; button text on accent 4.5:1). Hidden for predefined palettes.
  • Message list shows skeleton rows while a folder loads; theme / style changes cross-fade for 0.3s (disabled with reduced motion).
  • Fixes: the default RustBox selection colour (#28352e) is treated as automatic so the light theme keeps a light selection; subjects take priority over snippets in message rows; flagged messages use a red side bar; reader-toolbar button labels collapse below 820px.
  • Message rows already show label chips (message.tags).
  • Calendar: optional second reminder per event (reminder_extra_minutes, V054; choices from "at start" to "1 week before"), default reminders for new events in Settings → Notifications (calendar_settings.default_reminder_minutes / default_extra_reminder_minutes), both exported as VALARMs. All-day events are reminded relative to the working-day start (default 09:00). UpdateEvent now distinguishes an absent reminder from null, so clearing a reminder works.
  • The interface-style selector is grouped with <optgroup>s (labels translated through the scoped _text map) and uses short names; INTERFACE_SKINS follows the same order.

0.2.23 interface styles

  • Adds Appearance → Style depth (display_preferences.skin_depth, migration V053): colors applies only a predefined style's palette and leaves layout controls editable; standard (default) keeps the previous palette + fixed layout behavior; immersive additionally applies the style's structural tokens.
  • Adds Appearance → Style gradients (display_preferences.skin_gradients, same V053 migration, default off). Every gradient a style uses (immersive backdrops, app bars, primary buttons, the Synthwave logo, Roundcube Classic bevels in any depth) is scoped to html[data-skin-gradients="true"]; with the switch off the style uses flat fallback colors. The release validator rejects ungated gradients.
  • Interface-style standard: each predefined style has light and dark palettes (55-roundcube-skins.css, 56-interface-styles.css), a fixed layout profile (interfaceStyleProfiles) and a structural token block in 57-skin-tokens.css (fonts, heading treatment, control/button/compose/avatar radii, floating vs. flush panes, pane borders/shadows/glass, app bar and search field, sidebar colors, selection background/marker, row cards, primary/compose buttons, focus ring, bevels). 58-skin-immersive.css consumes the tokens only at the immersive depth; floating-pane geometry is limited to the desktop three-pane layout (>820px).
  • All 23 existing styles were adapted to the standard; 14 styles were added: Dracula, Catppuccin, Solarized, Gruvbox, Tokyo Night, Rosé Pine, Everforest, Synthwave, Paper, Terminal, Aqua Glass, Linear inspired, Material You inspired, Retro 95.
  • The style catalog lives in display_preferences::INTERFACE_SKINS and is shared by preference and default_interface_skin validation; scripts/validate-release-static.py checks catalog/selector/profile/palette/token parity.
  • V051 and V052 are consolidated into the fresh schemas (baseline V052). The fresh MySQL schema now uses an expression default for mail_preferences.message_loading_mode.

0.2.22 snooze and undo send

  • Adds message snooze: snoozed_messages (migration V052) is a local-only cache table — snoozing a message records a wake time and the client hides that message from its current folder view until then, via GET /folders/{name}/snoozed-uids; it has no IMAP side effects and does not touch server-side folder pagination/count SQL in routes/messages/mod.rs. POST/DELETE /messages/{folder}/{uid}/snooze set/clear a snooze, and GET /messages/snoozed lists everything currently sleeping across folders for the "View snoozed messages…" dialog. UI: a "Snooze…" context-menu entry and the b shortcut (message open) prompt for a duration; Shift+B opens the snoozed-messages list.
  • Adds an "Undo Send" window: a new undo_send_window_secs config knob (default 8, max 120 seconds; 0 disables it and restores immediate synchronous send). When enabled, a submitted message is staged in an in-memory UndoSendRegistry (src/undo_send.rs) instead of being dispatched immediately; the HTTP response returns right away with status: "pending", and a delayed task actually sends the message once the window elapses unless cancelled first. GET /messages/send/{pending_send_id} polls status (pending/dispatching/sent/cancelled/failed); DELETE /messages/send/{pending_send_id} cancels a still-pending send. Nothing is persisted: a server restart during the window loses the staged send, the same as an in-flight SMTP connection would be lost. The composer shows a toast with an "Undo" action and live countdown for the window.
  • Known limitation: a brand-new, never-autosaved compose that is sent and then left un-undone relies on the existing autosave/draft-recovery mechanism for recovery if the dispatch itself fails; this is not a new guarantee beyond what autosave already provides.

0.2.21 login hardening

  • Adds configurable login brute-force protection ([login_rate_limit]): per-IP token bucket plus per-mailbox and per-IP failed-attempt lockouts with exponential back-off; locked attempts return 429 + Retry-After before any IMAP connection
  • The public /api/auth/policy GET no longer consumes the per-IP login budget
  • Adds cookie_secure = auto | always | never; auto sets the cookie Secure attribute only for requests that really arrived over HTTPS, so plain-HTTP installs keep working
  • Adds attachment memory guards: attachment sets that cannot fit max_message_size_mb once MIME-encoded are rejected with 413 from stored sizes before any file is loaded (send, IMAP draft snapshot, attach-message, streaming upload), and max_concurrent_message_builds / message_build_wait_secs bound how many requests hold attachments in RAM at once
  • Adds Gmail-style message row opening: Ctrl/Cmd+click opens a message in a new tab, Shift+click opens it in a popup window, both deep-linked (outside selection mode; existing shift/ctrl selection behavior while selecting is unchanged)

0.2.20 browser mail UX

  • The forward-as-attachment route request extractor is crate-visible, matching the handler visibility required by the parent router and avoiding Rust private_interfaces/private-type build errors.

  • Mailbox message dates fall back to IMAP INTERNALDATE when the RFC 5322 Date header is missing/invalid; stale cached missing dates are repaired on folder access.

  • Forward-as-attachment creates a server-side message/rfc822 .eml attachment from the original IMAP RFC822 source.

  • HTML message previews use the full remaining vertical reader area and recompute their iframe height as reader chrome/layout changes.

  • Signature management uses equal-height text and HTML fields and includes a raw-HTML modal with a sanitized visual editor and inline image import.

  • Mail loading activity is represented by the app-bar spinner for pagination, progressive/full-folder retrieval and individual message/draft loading.

  • Shift-click selects a contiguous range in the visible message list, and pagination includes direct first/last page navigation.

  • Signature HTML formatting now preserves the selected text when toolbar controls are used, so bold/italic/underline and remove-format can be toggled reliably.

  • New messages with a visible signature always get an editable body line before the signature; the composer separator is spaced farther from the body and rendered as a subtle solid rule.

  • Wide message panes use a default-on compact single-line row layout (sender, subject/snippet, date and icons); users can disable it in Appearance settings.

  • Each identity can choose signature insertion: silent appends only during send and keeps the editor clean, while visible inserts an editable/removable signature into the composer.

  • Large To/Cc lists collapse to a compact recipient summary and expand on demand.

  • Mailbox loading defaults to pagination at 300 messages per page. Users can switch to smooth progressive loading or explicit full-folder loading in Mailbox settings.

  • The composer can collapse From/To/Cc/Bcc/Subject/options from its header so the editor receives the freed vertical space; invalid recipient input automatically reopens the fields.

  • The composer exposes an explicit Save draft action before Cancel; it forces a real IMAP Drafts snapshot with the current MIME body and attachments while background autosave remains local/server-working-state only.

  • The composer exposes Delete draft for IMAP and recovered drafts; deletion verifies the current IMAP UID/UIDVALIDITY, expunges the server draft first, then removes the local autosave row, cascaded attachment rows and uploaded attachment blobs.

  • HTML composing embeds newly added PNG/JPEG/GIF/WebP images inline by default while preserving deleted inline content as reusable attachments.

  • Attachment chips can re-embed images or insert CID links for other files, and selected inline images expose quick size/alignment controls plus the advanced crop editor.

  • Clipboard image paste and file drag/drop insert at the current/drop caret; already embedded images can be dragged to a new body position.

  • Selected inline images expose four pointer resize handles that preserve aspect ratio, and attachment chips distinguish image attachments from ordinary files.

  • Message-body links without an explicit target default to target="_blank" so external navigation opens outside the sandboxed mail-preview iframe; explicit targets are preserved and _blank links receive noopener noreferrer.

  • Login success is shown only after a real login request; refreshing/restoring an existing authenticated session is silent.

  • Message/HTML preview documents explicitly declare UTF-8, and encoded-word header decoding delegates first to mail-parser for broader charset coverage, including UTF-8, ISO-8859-2 and Windows-1250 subjects and display names.

  • PDF attachments are previewed from the authenticated inline attachment URL instead of a blob: iframe, improving Safari/iPhone compatibility.

  • Composing displays attachment/message size limits as one compact line without configuration/MIME implementation details.

  • Initial synchronization remains silent for new-mail notifications; bulk operations retain one summary toast; browser/system modifier shortcuts remain preserved.

  • Mailbox pagination is enabled by default at 300 messages per page; the API/preferences accept page sizes up to 300, with progressive and load-all alternatives.

  • Blob deletion uses a durable SQL outbox for filesystem/shared POSIX/NFS and S3 backends; attachment/draft metadata deletion is transactionally paired with cleanup enqueue and failed deletes retry in the background.

  • V047-V052 are consolidated into the V052 compatibility baseline (0.2.23). V053 adds skin_depth and skin_gradients to existing V052 tenants; V054 is next.

0.2.8 browser security headers

  • security_headers_enabled remains opt-in and disabled by default for compatibility; optional browser-security headers are centralized in this middleware, so disabling it removes the RustBox-added security profile while normal response semantics such as Content-Type and route-specific caching remain.
  • HTML/XHTML documents receive the full document profile: CSP, X-Frame-Options: DENY, Permissions-Policy, Cross-Origin-Opener-Policy: same-origin, Referrer-Policy: no-referrer and X-Content-Type-Options: nosniff.
  • The HTML CSP allows only same-origin scripts (script-src 'self') and disables inline script attributes; the theme bootstrap is an external fingerprinted asset. Stylesheets are same-origin only (style-src 'self'), while style-src-attr 'unsafe-inline' is narrowly retained because the current UI still sets per-element style attributes dynamically.
  • Private /api responses receive Cache-Control: no-store, X-Content-Type-Options: nosniff and Cross-Origin-Resource-Policy: same-origin. API responses are normally non-frameable (frame-ancestors 'none' / X-Frame-Options: DENY); application/pdf is the narrow exception and allows same-origin framing for the attachment preview (frame-ancestors 'self' / SAMEORIGIN). API JSON does not receive the full document CSP, Permissions-Policy, COOP or Referrer-Policy.
  • CSS receives Referrer-Policy: no-referrer and X-Content-Type-Options: nosniff; application assets also receive same-origin CORP without redundant HTML document policies.
  • HSTS is deliberately not synthesized by RustBox because the application may sit behind a TLS-terminating reverse proxy and cannot reliably determine the public HTTPS boundary; HSTS belongs at that HTTPS edge.
  • The public /api/auth/policy is data-minimized to the single login-form capability rememberMeEnabled. Optional feature availability (OpenPGP, Sieve, diagnostics, About, multi-account sessions) is returned only from authenticated /api/auth/session-policy; session/remember durations are not exposed to the browser policy endpoints.

0.2.8 storage/search architecture

  • SQL backend selection (sqlite/mysql/pgsql) is independent from blob storage and search backend selection.
  • Cluster mode clears an implicit/default data_dir; PostgreSQL/MySQL single-node deployments may still intentionally use data_dir-backed filesystem storage and local Tantivy.
  • Blob storage supports local/shared POSIX filesystems and S3-compatible object storage. Shared POSIX is an explicit capability (storage.shared=true) suitable for operator-provided NFS/CephFS/GlusterFS mounts.
  • Draft attachment upload/read/delete/snapshot/send paths use the BlobStorage abstraction and logical object keys instead of assuming node-local paths.
  • OpenSearch is available as the cluster-capable indexer. Local Tantivy remains single-node only; search may also be disabled.
  • Search mutations use a durable SQL outbox with claim/lease, retry/backoff and dead-letter state; the index remains rebuildable derived state.
  • The V050 compatibility baseline includes the former V047 attachment/search-outbox changes, V048 folder counter generation, V049 blob deletion outbox and compact-row/signature preferences. V051 adds adaptive HTML-mail colors and mailbox loading mode; V052 is reserved as the next migration number.
  • SQL global-schema initialization is centralized in db::pool::configure(); database-backed sessions do not repeat startup DDL for SQLite, MySQL or PostgreSQL.
  • Docker Compose examples cover standalone SQLite, PostgreSQL + SILO (S3-compatible) + OpenSearch, and MySQL + NFS + OpenSearch.
  • Live SILO/MinIO/AWS S3/Ceph RGW, live NFS multi-host, live OpenSearch and full multi-node failover acceptance remain release-environment validation items and are not represented as completed here.

Implemented / wired in this working snapshot

Runtime

  • Single Rust runtime with embedded HTML/CSS/vanilla-JavaScript UI.
  • No TypeScript, React, Next.js, Node.js or Bun product build/runtime.
  • EN/PL language assets embedded in the binary.

Mail and IMAP workflow

  • Folder totals and unread counters use authoritative IMAP STATUS (... MESSAGES UNSEEN ...) data. If STATUS is unavailable for a selected mailbox, RustBox falls back to UID SEARCH UNSEEN; it never treats SELECT/EXAMINE UNSEEN (the first unseen sequence number) as an unread count.
  • Folder counter reconciliation runs independently from content synchronization and repairs MESSAGES/UNSEEN even when HIGHESTMODSEQ is unchanged. A manual counter refresh reuses the cached folder tree while it is fresh and batches STATUS calls on one IMAP session instead of forcing another LIST.
  • Read/unread/flag mutations update the affected row/badge optimistically, then reconcile against authoritative IMAP state and publish targeted flag/FolderStatus events without replacing the whole message list. The active folder is watched through IMAP IDLE; other folders are reconciled every 30 seconds.
  • Large folders may hydrate message headers incrementally, but the sidebar total/unread badge remains server-authoritative. IDLE/periodic reconciliation keeps the CONDSTORE cursor separate from counter refresh, falls back to a full UID FLAGS comparison when CONDSTORE is unavailable, and discards partial IMAP fetch streams rather than applying incomplete state. The top-right activity indicator distinguishes active synchronization/indexing from an incomplete local IMAP header cache and exposes backlog details in its tooltip.
  • Wide folder badges display total / unread while unread is non-zero and total alone at zero; narrow sidebars switch to the compact existing counter presentation.
  • IMAP folder list, hierarchy, create, create subfolder, rename, delete, subscribe/unsubscribe, plus collapsible branch navigation with per-account remembered expansion state.
  • Special folders stored per account: Sent, Drafts, Trash, Junk and Archive. Spam/Junk additionally supports a browser-wide default destination with a per-account override and IMAP special-use/name fallback.
  • Special-folder references follow folder renames and are cleared when a referenced folder is deleted.
  • Administrators can define server-wide default Sent/Drafts/Trash/Junk/Archive folder names; per-account settings still override them when present.
  • Sent-copy, delete-to-Trash, Archive and Junk actions use the configured special folders.
  • Mark-all-read and empty-folder operations.
  • Message move and copy operations.
  • Multi-select and bulk read/unread, flag/unflag, archive, move, copy, label and delete actions, including explicit select-all across the complete cached search result set.
  • Drag-and-drop a message onto a folder to move it.
  • Previous/next message navigation plus keyboard actions for common reader operations, compose, selection mode and selecting the current message.
  • After moving/deleting the currently opened message (including Spam, Not spam, Archive and Move), the reader automatically opens the next list item and falls back to the previous item when the removed message was last.
  • Message reading, collapsible thread navigation, attachments, raw headers, full RFC822 .eml download via BODY.PEEK[] and .eml import into a selected IMAP folder via APPEND.
  • Message/folder context menus with common Roundcube-style actions, including folder properties, full message source, Message-ID/address copy and mailing-list unsubscribe; the reader sender line also exposes compose/contact/search/filter actions.
  • Mailbox quota display where the IMAP server exposes quota, including warning/danger states at 80%/95%. The storage summary opens a per-folder usage view backed by IMAP message sizes, and folder properties expose the measured size when the server permits the read.
  • Per-account mailbox behavior: 20/50/100/200 messages per page, date/sender/subject/size sorting in both directions, configurable mark-read delay, threaded/flat reader mode, HTML/plain preference, remote-image policy including Contacts-only loading, quote limiting, optional list snippets and a default “flagged on top” mode. Each folder can inherit, force-enable or force-disable flagged-first ordering; sorting is applied before pagination.
  • IMAP capability diagnostics for IDLE, MOVE, UIDPLUS, CONDSTORE, QRESYNC, SORT, THREAD, NAMESPACE, SPECIAL-USE, QUOTA, ACL, LIST-EXTENDED and UTF8=ACCEPT.
  • Forward-as-attachment using message/rfc822.
  • Mailing-list unsubscribe action from List-Unsubscribe; RFC 8058 one-click HTTPS requests are sent by the backend only when List-Unsubscribe-Post: List-Unsubscribe=One-Click is advertised, with redirect-free public-address SSRF checks. Ordinary HTTPS/mailto links remain user-confirmed UI actions.
  • Explicit upload-body limits for attachments, contact imports/photos, ICS imports and .eml import so Axum does not reject allowed uploads at its smaller default limit.
  • Attachment context menu supports in-app preview/download for safe image/PDF/text/HTML/video classes; HTML is sandboxed and video uses native browser controls. Multiple attachments can be downloaded as a client-built UTF-8 ZIP without external runtime dependencies.
  • Message rows expose compact hover/focus quick actions for read/unread and flag/unflag; flagged rows also receive a subtle red lower-edge marker.

Composer / identities

  • HTML, plain-text and Markdown compose modes. Markdown keeps its source text for the plain alternative and generates escaped/sanitized HTML for preview and delivery without accepting raw Markdown HTML.
  • Expanded HTML toolbar: bold, italic, underline, strike, lists, quote, alignment, links, font, size, color, clear formatting, undo/redo.
  • Draft autosave, explicit recovery of saved/browser-emergency drafts, and attachment upload/delete. IMAP Drafts messages are also first-class editable drafts: RustBox opens their RFC822/MIME content directly from IMAP (including external-client drafts), stages only the normal autosave/recovery state locally while editing, and replaces the source UID only after the new snapshot is appended and resolved safely. X-RustBox-Draft-ID remains an internal UID-resolution aid for RustBox-created snapshots, not a prerequisite for opening or editing a draft.
  • Drag-and-drop attachments with visible upload progress. Attachment uploads stream multipart chunks through BlobStorage with an enforced size limit instead of buffering the whole attachment in memory; filesystem and S3-compatible backends share the same logical-object flow.
  • Inline image upload using CID attachments, including paste and drag/drop of PNG/JPEG/GIF/WebP images into the composer. During editing, CID images use authenticated same-origin draft-attachment preview URLs and are serialized back to cid: references for saved/sent MIME content. Inline images can be resized, aligned left/center/right/inline and cropped in-app (GIF cropping is intentionally disabled to preserve animation); display-only resizing does not rewrite the source file. Unused CID attachments are cleaned when their image is removed from the editor.
  • Attachment reminder for common English/Polish wording.
  • Multiple identities.
  • Identity Reply-To, automatic Bcc, Organization metadata, text/HTML signatures and per-action signature rules/position; replies/forwards auto-select the matching identity from To/Cc/Delivered-To/Envelope-To when possible.
  • Composer From identity selection and signature insertion.
  • Outgoing priority (normal/high/low) and MDN/read-receipt requests are persisted in drafts and emitted consistently in SMTP delivery and the IMAP Sent copy; all envelope/header mailboxes are parsed before SMTP delivery. Administrators can also configure validated additional outgoing headers; structural/MIME headers and CR/LF-injected values are rejected.

Search, labels and contacts

  • Tantivy/search backend retained.
  • Search operators including from:, to:, subject:, folder:, has:attachment, is:read, is:unread, is:flagged, is:unflagged and date filters. Active search terms are highlighted in sender, subject and snippet text using DOM text nodes rather than result HTML.
  • Advanced-search dialog and saved searches.
  • User labels/tags with validated HEX colors, message chips, context actions and bulk assignment. Optional native IMAP-keyword synchronization writes stable RustBox keywords only on folders advertising persistent custom-keyword support, imports observed RustBox keywords and provides an authoritative reconcile action that also applies remote removals only on confirmed keyword-capable folders.
  • Contacts CRUD/search with phone, job title, postal address, website and birthday fields.
  • Contact photo upload/remove/display (PNG/JPEG/WebP, 2 MB limit, MIME signature validation).
  • Contact groups, membership editing and group filtering.
  • vCard import/export includes the expanded profile fields and multiple e-mail/phone/address values.
  • Duplicate-contact detection checks primary and alternate e-mail addresses; merge keeps target data, alternate values, group memberships and a source photo when the target has none.
  • vCard attachments can be imported directly from a message attachment.
  • Composer To/Cc/Bcc fields use the existing contact/known-address autocomplete API with keyboard navigation.

Sieve

  • ManageSieve raw script list/get/put/delete/rename/activate/deactivate/check.
  • STARTTLS, implicit TLS and explicit plaintext opt-in.
  • Quick filters generated from sender/domain/subject use an in-app wizard with condition/action preview, capability-aware actions, optional mark-as-read chaining, target-script selection, server validation and direct save/activation; an Advanced editor handoff remains available. The wizard explicitly states that Sieve changes apply to future incoming messages.
  • Visual rule builder with From/domain/To/Subject/List-ID/custom-header conditions, three-condition nested AND/OR grouping and per-condition negation.
  • Visual actions: move, copy, redirect, discard, mark read, add IMAP flag and keep, with an optional second action.
  • RustBox-generated visual rules carry stable markers and can be reordered by drag/drop or keyboard-accessible up/down controls without rewriting unrelated raw-script text.
  • Builder merges require extensions, disables actions unsupported by advertised server capabilities and validates generated scripts with the server.
  • Autoresponder/vacation builder supports subject, body, reply interval, mailing-list/automated-mail suppression and optional inclusive start/end dates using currentdate when the server advertises date + relational.
  • Sieve scripts can be backed up/restored as a validated RustBox JSON bundle; restore validates all scripts before writing, and saving over an active script requires an explicit application confirmation.

Calendar and realtime

  • Calendar event CRUD UI with Month, Week, Day and Agenda views.
  • iCalendar/ICS import UI over the existing parser/backend, plus direct import from message attachments and full local ICS export.
  • Calendar event editor includes all-day mode, RRULE storage, attendees, organizer, status, reminder, meeting URL and color metadata.
  • Browser WebSocket client connected to the existing IMAP IDLE/event backend.
  • Realtime folder/message refresh for NewMessages/FlagsChanged/FolderUpdated events.
  • Desktop notifications, optional sound, per-folder selection and persisted Do Not Disturb hours. Aggregate unread count updates the browser-tab title and the application badge where the Badging API is available.
  • Account switch/remove/add workflow for multiple authenticated accounts in one browser session.
  • Active-session list across browsers while the RustBox process is running, with creation/last-active timestamps, friendly browser/device labels, full User-Agent hover detail, individual revoke and revoke-all-others.
  • Diagnostics panel exposing IMAP capabilities (including persistent custom-keyword support), authenticated SMTP connectivity, ManageSieve status, browser WebSocket state, local synchronization-cache timestamps/counts and live IMAP IDLE task/subscriber counts without returning server host names or credentials. Public liveness (/api/health) and local-storage readiness (/api/ready) endpoints are available for service supervision.
  • Optional administrator system diagnostics endpoint (disabled by default) supports explicit IP/CIDR allowlisting plus token/Basic authentication, redacts configured secrets, probes SQL/session/storage/search backends, reports active sessions and IMAP IDLE state, and surfaces bounded node-local security signals for failed logins, 403/429 responses and 5xx failures.
  • Search-index diagnostics expose cached/indexed counts, with a rebuild operation from the configured account-data backend.
  • IMAP reconnect control drops reusable request-path sessions and verifies a fresh authenticated connection.
  • Graceful SIGTERM/Ctrl+C shutdown stops accepting new requests and aborts dedicated IMAP IDLE tasks before process exit.

Personalization

  • Persistent per-user display preferences in the configured application database.
  • Light/dark/system theme.
  • Presets: sage, blue, teal, cyan, indigo, slate, graphite, amber, orange, violet, rose, red and custom.
  • Custom accent, background, panel and text colors.
  • Font family and size, message row height, folder/message pane widths, border radius and contrast. Advanced controls include icon size, toolbar/sidebar density, reader/composer widths, selection color, unread font/badge styling, compact headers, border visibility, scrollbar density, monochrome mode and per-pane background overrides.
  • Date-format (locale/ISO/EU/US) and time-format (locale/24-hour/12-hour) preferences.
  • Compact/comfortable density, preview right/bottom/off, UI scale and reduced motion.
  • Avatar/attachment/flag visibility toggles.
  • Folder and message-list pane widths can also be adjusted directly with draggable splitters and persist through the existing per-user display preferences. Keyboard shortcuts are documented in an in-app reference dialog.

Build/installation fixes in this snapshot

  • Fixed the E0499 mutable-borrow failure in mark_all_read: the uid_store() stream is dropped before session.logout().
  • Fixed a duplicate else introduced in the calendar delete handler during the calendar expansion.
  • All executable Rust SQL is centralized under src/queries/{sqlite,mysql,pgsql}/queries.rs, including session queries.

Partially implemented - keep visible as incomplete

  • Sieve visual builder now supports a three-condition nested AND/OR group, negation, two actions, capability-aware disabling, managed-rule ordering and scheduled vacation dates. An arbitrary-depth condition tree, arbitrary-length action stack and full capability-aware condition/action matrix remain unfinished.
  • Composer autosave/recovery state is stored locally, while deliberately saved drafts are standard RFC822/MIME messages in the configured IMAP Drafts folder. IMAP drafts from RustBox or another client open directly in the composer; replacement is conservative (append/resolve first, then remove the prior UID after UIDVALIDITY verification). Wider real-server compatibility still needs the release gate.
  • Calendar is local/ICS-capable and stores recurrence/attendee/reminder metadata, but recurrence expansion/edit semantics, invitation responses and CalDAV synchronization are not finished.
  • Notifications are wired through IMAP IDLE/WebSocket, include permission status/test controls, and local calendar reminders can show browser notifications and play the configured sound while RustBox is open. Service-worker/background delivery is still not finished.
  • Identities emit Organization metadata; composer priority, MDN request headers and validated administrator-defined outbound headers are wired. SMTP DSN negotiation remains to be completed.

Not yet complete - do not claim Roundcube parity

  • MOVE-based Undo is available for move/delete-to-Trash/archive/spam when the destination UID can be resolved unambiguously from pre-MOVE UIDNEXT plus exact Message-ID. A persistent multi-step undo history and servers/messages without a safely resolvable destination UID remain unfinished.
  • Contact model supports multiple e-mails/phones/addresses and duplicate merge UI; CardDAV and LDAP synchronization/UI remain.
  • OpenPGP roadmap scope is implemented end-to-end: per-user keyring, generate/import/export/delete, passphrase test/change, identity binding, sign/encrypt/sign+encrypt, PGP/MIME + inline PGP, verify/decrypt, trust/fingerprint UI, WKD and optional HTTPS HKP. Real cargo test and interoperability regression coverage are still release-gate work.
  • TNEF/winmail.dat decoding and full SMTP DSN negotiation are still not implemented. SMTPUTF8/IDN behavior still requires the real-server compatibility matrix from the release plan.
  • IMAP ACL/shared-folder management and full capabilities settings UI remain the next major protocol block.
  • Spam backend adapters for rspamd/SpamAssassin/custom command.
  • Calendar Month/Week/Day/Agenda views are present; recurrence expansion/exceptions, invitation response workflow and CalDAV remain.
  • Full CardDAV synchronization.
  • Password-change adapters remain unfinished. Session inventory/device metadata is now persistent across restarts and shared-session backends support cross-node listing/revocation.
  • Diagnostics now includes IMAP reconnect, SMTP connectivity, index rebuild and last local folder/message synchronization metadata; deeper background task/queue metrics and repair workflows remain.
  • Full live security, acceptance and performance matrix remains release-environment work tracked in TODO.md.

UI reliability / workflow fixes in the current snapshot

  • Contact editor, calendar, raw-header and message-source dialogs use viewport-bounded layouts with independent scrolling and non-overlapping actions. Generic dialogs also fall back to whole-card scrolling when their content exceeds the browser workspace. Settings uses an explicit header + flexible-content grid so short panels no longer push the navigation/content block toward the bottom of the modal; settings navigation/content scroll independently when needed.
  • Month calendar grid and toolbar layout are responsive and remain usable under browser/UI scaling.
  • UI scale now affects font size, row height, pane widths, icons, field/button padding and control/header dimensions without being overwritten by the separate font-size setting.
  • Responsive layout keeps user-selected folder/message pane widths within safe viewport bounds instead of reverting to fixed widths.
  • The mobile composer keeps address labels and controls aligned, and the mobile folder drawer can be closed by its toggle, backdrop, Escape or folder selection while hierarchy disclosure controls keep larger touch targets.
  • Application actions have reusable success/error/warning/info toast feedback, including from within native modal dialogs.
  • Primary and bulk message toolbars include Spam / Not spam, driven by the configured Junk folder.
  • Reader includes Print, Source viewer and quick Create-filter-from-sender actions.
  • Reader addresses expose one-click contact actions; trusted senders can be added from a message so remote images load automatically unless the global policy is Never.
  • Header viewer shows a structured common-header summary and the raw header block.
  • vCard/iCalendar attachment SVG action icons no longer leak their markup as visible text; reader cleanup also strips only RustBox-owned icon-sprite fragments from malformed MIME content.
  • Message HTML receives an additional client-side sanitization pass before sandboxed iframe rendering; plain text is preserved exactly.
  • Embedded CSS/JS use content-fingerprinted URLs with Cache-Control: public, max-age=31536000, immutable; HTML and unversioned compatibility aliases remain no-store.
  • Native browser confirmation/text prompts are no longer used by the main UI workflows; destructive actions and folder/label/text choices use RustBox application dialogs.
  • Message selection has an explicit mode: per-row checkboxes only appear while selecting, with select-all and bulk actions grouped in the selection toolbar.
  • Search selection can materialize and select every cached matching result, not only the currently rendered page.
  • Folder/message list state now preserves the last folder, loaded-page depth and scroll position; active searches also retain their query and scroll position during normal realtime/refresh flows.
  • Network failures surface an offline/reconnecting banner. Only idempotent GET/HEAD requests receive bounded automatic retries; send/move/delete and other mutating requests are never auto-replayed.
  • Toasts with actions keep Undo and the close button adjacent in a dedicated action group so closing a toast cannot trigger Undo.
  • MOVE-based actions expose a toast Undo only when the backend can identify the server-assigned destination UID without guessing; bulk Undo reverses resolved moves in reverse order.
  • Thread lookup now validates complete References Message-ID tokens after the SQL candidate query, preventing partial-ID false matches.
  • Safe attachment previews stay inside a RustBox modal instead of opening a browser popup.
  • Composer uploads expose progress, clipboard images become CID inline attachments, and browser-local recovery preserves edits when a draft save fails.
  • Compact/comfortable density now visibly affects controls/toolbars/dialog headers without overwriting the separate row-height and pane-width preferences.
  • Toasts show the remaining auto-dismiss time and pause their countdown while hovered or keyboard-focused.
  • Appearance uses persisted interface_skin modes for RustBox (custom), Roundcube Classic, Roundcube Larry, Roundcube Elastic, Clean, Graphite and High contrast. The old Compact/Balanced/Comfortable/Reading preset cards were removed. Fixed interface styles apply their own visual geometry and palette without overwriting the user's stored RustBox custom values; selecting RustBox re-enables manual color, spacing, pane and typography controls. Classic Dark remains an adaptation because upstream Classic has no official dark skin.
  • Composing settings now persist the default format, autosave interval, default priority, default read-receipt request, attachment-reminder behavior, default font, reply placement, quote style, forward mode and browser spellcheck through display preferences. Saved/canned responses can be managed as text or sanitized HTML and inserted from the composer toolbar.
  • Message Print uses an in-page print frame instead of a popup and prints sanitized HTML or plain text with From/To/Date metadata.