43 KiB
RustBox changelog
0.2.4
- Fixed S3-compatible storage over explicitly allowed plain HTTP endpoints by applying
storage.allow_httpto the finalClientOptionsobject instead of setting it beforewith_client_options()replaces those options. This fixes Garage/MinIO/Ceph-style internal HTTP endpoints without weakening the HTTPS default. - Added an HTTP S3 regression test that verifies a request reaches an explicitly allowed local S3-compatible endpoint.
- Updated the pinned Rust toolchain/MSRV to Rust 1.99.1.
- Updated RustBox Docker build/runtime images from Debian 12 Bookworm to Debian 13 Trixie (
rust:1.99.1-trixie,debian:trixie-slim) and switched the runtime OpenSSL package to Trixie'slibssl3t64. - Updated PostgreSQL 17 Compose images from Bookworm to the supported Trixie variant.
- No schema migration is required; runtime schema remains V047 and V048 remains the next migration number.
- Bumped the application/source release to 0.2.4.
0.2.3
- Fixed API fallback routing so administratively disabled or otherwise unknown
/api/*endpoints return HTTP 404 instead of being caught by the SPA fallback and returning the UI with HTTP 200. - Added administrator feature switches for ManageSieve, diagnostics and About; disabled Sieve/diagnostics routes are not registered, and the matching settings UI is removed while keyboard shortcuts remain available.
- Added a protected “Reset all settings” action that restores display, mailbox, notification, folder, special-folder, calendar and OpenPGP preferences without deleting mail, identities, keys, templates or trusted-sender data.
- Added opt-in browser security response headers (CSP, frame, referrer, permissions and cross-origin opener policies); the feature is disabled by default for compatibility.
- Added a Docker HA example with two RustBox application nodes behind Envoy round-robin load balancing, Valkey-backed sessions, PostgreSQL, OpenSearch and Garage S3 object storage. Envoy adds
X-RustBox-Backendto responses. - Added current pinned Garage, Valkey and Envoy images to the HA example and an idempotent Garage bucket/key initialization helper.
- No schema migration is required; runtime schema remains V047 and V048 remains the next migration number.
- Bumped the application/source release to 0.2.3.
0.2.2
- Fixed the SQLite isolation regression test to initialize
AppConfigwith a struct literal plus..Default::default(), satisfyingcargo clippy --all-targets -- -D warningswithout suppressingfield_reassign_with_default. - Fixed Rust test isolation for SQLite: test-only
db::pool::configure()still initializes the requested database schema but no longer pins the first temporary SQLite path in the process-wideOnceLock, preventing later tests from reusing a deletedTempDirand collapsing into HTTP 500/database-open failures. - Added a regression test that configures SQLite in one temporary directory, removes it, then opens an account database in a second temporary directory.
- Strengthened the offline release contract to assert that
scripts/build-release.shrequires the full locked test suite, warning-free Clippy, and a locked release build before a release is accepted. - Fixed the PostgreSQL startup schema compile failure (
implementation of sqlx::Executor is not general enough) by executing the multi-statement DDL batch throughsqlx::Executor::execute()on the transaction connection instead ofsqlx::raw_sql(...).execute(&mut PgConnection). - Preserved transactional startup schema initialization and the local
client_min_messages=WARNINGscope used to suppress expected idempotent PostgreSQL NOTICE output. - Added a static regression gate that forbids the lifetime-problematic
raw_sql(&schema).execute(&mut *tx)PostgreSQL startup path. - No schema migration is required; runtime schema remains V047 and V048 remains the next migration number.
- Fixed PostgreSQL header-sync invalidation used by message mutations (including marking/moving messages as spam): the UPSERT now qualifies the existing tenant
user_meta.value, avoidingcolumn reference "value" is ambiguousand HTTP 500 responses. - Added a regression check for tenant SQL rewriting of the qualified
user_meta.valuereference and a static audit covering all PostgreSQLON CONFLICT ... DO UPDATEtarget-column reads. - Confirmed the equivalent SQLite UPSERT is not ambiguous and MySQL uses
ON DUPLICATE KEY UPDATE, so no matching backend fix is required. - No schema migration is required; the runtime schema remains V047 and V048 remains the next migration number.
- Centralized SQL schema initialization in
db::pool::configure()so the database session store no longer executes the global schema a second time. - Fixed the duplicate startup DDL for all SQL backends: PostgreSQL no longer repeats
relation ... already exists, skippingnotices, while MySQL and SQLite also avoid the redundant second schema pass. - Scoped PostgreSQL startup schema initialization to a transaction with
client_min_messages=WARNING, suppressing expected idempotentCREATE ... IF NOT EXISTSnotices without hiding application/database warnings globally. - Removed the Docker-specific SQLx PostgreSQL notice filter workaround; normal
RUST_LOG=infois sufficient. - No schema migration is required; the runtime schema remains V047 and V048 remains the next migration number.
- Release number kept at 0.2.2 for this cumulative patch set.
0.2.1
- Fixed Docker development authentication by documenting and defaulting Compose to
ENVIRONMENT=development, so session cookies work over direct HTTP while production keepsSecurecookies behind HTTPS. - Exposed
pgp_enabledthrough the auth policy and hid OpenPGP settings, identity controls, composer controls and reader UI when OpenPGP is disabled by administrator policy. - Prevented disabled OpenPGP from producing repeated UI error toasts or unnecessary API requests.
- Added OpenSearch outbox worker backoff for HTTP 429/flood-stage/read-only conditions and stopped the current batch after the first backpressure failure, preventing log storms while preserving durable retries without consuming dead-letter attempts.
- Kept OpenSearch disk safety thresholds intact; Docker documentation explains that named volumes consume the Docker host filesystem and how to diagnose/recover flood-stage blocks.
- Added a stable
rustboxCompose project name, documented Docker environment variables, and made application port mapping configurable throughPORT. - Reduced PostgreSQL startup log noise in the Docker example by suppressing repeated SQLx
NOTICEmessages at the default log filter. - Bumped the application/source release to 0.2.1.
0.2.0
- Fixed nested database transactions during message move by reusing the caller-owned transaction for cache removal, header-sync invalidation, folder invalidation, and search outbox writes.
- Kept
search_outboxin sync between tenant and legacy-import table sets so schema/import parity tests pass. - Decoupled SQL, blob storage and search: PostgreSQL/MySQL may still use local
data_dirbackends in single-node mode, while cluster mode no longer requires persistentdata_dirwhen cluster-safe backends are configured. - Added
BlobStoragewith filesystem/shared-POSIX and S3-compatible backends, streaming attachment I/O, SHA-256 metadata, S3 retry/timeouts/checksums/SSE options and storage readiness probes. - Added idempotent attachment migration from legacy filesystem paths to logical object keys (
rustbox storage migrate). - Added OpenSearch as the external full-text backend with an async HTTP client, per-tenant filtering/routing, deterministic document IDs, health checks and rebuild support.
- Added a durable SQL search outbox with caller-transaction participation, claim/lease concurrency, retry/backoff, dead-letter state and lag/dead-letter diagnostics.
- Hardened clustered indexing against re-enqueue/lease races, sized worker leases from the OpenSearch timeout/failover budget, and made IMAP IDLE deletions enqueue index removals in the same SQL transaction.
- Added runtime schema migration V047 for attachment checksums and the search outbox across SQLite, MySQL and PostgreSQL.
- Added Docker variants for standalone SQLite, PostgreSQL + SILO (S3-compatible) + OpenSearch, and MySQL + NFS + OpenSearch.
- Added tests for cluster capability validation, filesystem blob streaming, OpenSearch tenant scoping and search-outbox transaction rollback/claim/idempotency behavior.
- Bumped the application/source release to 0.2.0.
0.1.2
- Added
log_levelto TOML configuration (trace,debug,info,warn,error,off);RUST_LOGremains an explicit runtime override. - Audited the MySQL and PostgreSQL query catalogs, schema baselines and backend-specific server SQL without adding application tests.
- Fixed a MySQL DDL incompatibility by changing indexed
pgp_keys.emailfromTEXTtoVARCHAR(320); MySQL requires a prefix length when indexingTEXT/BLOBcolumns. - Fixed destructive MySQL cache upserts: folder refresh and message-header refresh now use
INSERT ... ON DUPLICATE KEY UPDATEinstead ofREPLACE INTO, preserving child rows, message tags, cached bodies and other columns not part of the refresh. - Documented and enforced cluster storage behavior: mailbox metadata/body cache remains in shared SQL, while draft attachments use either S3-compatible storage or an explicitly shared POSIX filesystem.
- Replaced the pre-0.2 storage/search compatibility switches with the final
[storage]and[search]configuration model; cluster mode validates backend capabilities directly and rejects local Tantivy. - Added
pgp_enabled; cluster mode requires OpenPGP disabled because private-key material is filesystem-backed. - Avoided provisioning per-user Tantivy directories when the search index backend is disabled and made diagnostics/deep indexing honor that setting.
- Added a release audit document with SQL compatibility and distributed-storage findings.
- Bumped the application/source release to 0.1.2.
0.1.1
- Fixed the multi-backend compatibility layer compile blockers reported by the Rust compiler: empty
[]parameter inference no longer overlaps the generic array implementation, legacy SQLite probing importsrusqlite::OptionalExtensionwithout colliding with RustBox's ownOptionalExtension, and MySQL/PostgreSQL transaction batch execution now uses the typed SQLx transaction helpers instead of the lifetime-problematicraw_sqlexecutor path. - Unified the storage model:
database_backend = sqlite | mysql | pgsqlnow selects the database engine for the whole application instead of only the SQL session store;session_backend = database | rediseither keeps sessions in that same database or moves them to Redis/Redis Sentinel. - Added complete SQLite, MySQL and PostgreSQL baselines under
migrations/{sqlite,mysql,pgsql}/schema.sql. Each schema contains global sessions plus the full account-data schema at baseline version 46; the historical SQLite V001-V046 files are squashed out of the release tree and V047 is reserved for the next schema change across all engines. - Preserved per-account data isolation in a shared physical database with deterministic collision-checked table prefixes, while keeping the session table global.
- Added automatic first-use import of legacy 0.1.0
data_dir/<user_hash>/db.sqlitedatabases atPRAGMA user_version = 46into the configured backend. The source database is renamed todb.sqlite.pre-0.1.1.bakonly after a successful import; older schemas are rejected with an explicit upgrade requirement. - Added a backend-neutral database compatibility layer used by the existing Rust data modules and switched application query selection to the SQLite/MySQL/PostgreSQL catalog matching the configured backend.
- Corrected MySQL/PostgreSQL query dialects and parameter handling, including numbered/reused parameters, upsert syntax, timestamp expressions, JSON address lookup and generated-ID handling.
- Fixed transaction scope for server databases so cache/message synchronization, header invalidation and other grouped writes execute on the actual MySQL/PostgreSQL transaction connection rather than accidentally falling back to the pool.
- Removed separate
session.sqlfiles: sessions are part of each engine's completeschema.sql; Redis remains schema-less. - Removed stale Python release-contract tests and the unused HTML fixture; retained the runtime JSON fixture used by Rust tests and added native tests for tenant scoping, placeholder adaptation and legacy SQLite import.
- Made Oxi synchronization treat upstream
backend/migrations/andbackend/tests/as RustBox-owned review-only areas so schemas and native tests are never overwritten automatically. - Removed the accidental runtime log
qar.txtfrom the source tree and refreshed release metadata for 0.1.1.
0.1.0
- Cleaned the final release gate for Rust 1.99 Clippy with
-D warnings: refactored persistent session creation into a typed input struct and fixed all reported collapsible conditionals, redundant closures, needless borrows/question marks, test layout and collection checks without disabling Clippy globally. - Fixed fresh user-database provisioning so only SQLite user migrations
V001-V046are applied; session migrationV047is now exclusively owned by the configured session-store backend and MySQL SQL can no longer be executed against a user SQLite database. - Removed the obsolete Refinery migration path/dependency and its
refinery_schema_historybridge; RustBox now has one canonical user-database migration runner. - Removed unused test-only session removal helpers that emitted
dead_codewarnings duringcargo test. - Strengthened
scripts/build-release.shto require formatting, locked tests, Clippy with-D warnings, and a locked release build before producing a release binary. - Removed production-build warning noise from the multi-dialect query catalogs without disabling warnings crate-wide; test-only session/SMTP helpers are now compiled only under
cfg(test). - Fixed cached-message row decoding after the query-catalog refactor: message list queries now project the exact
CachedMessagecolumn order (flags,size,has_attachments,snippet,reaction) across SQLite/MySQL/PostgreSQL. - Fixed Rust
macro_rules!query hygiene errors by passing dynamic SQL fragments and parameter indexes explicitly into SQLite query macros instead of capturing caller-local variables. - Fixed the
libsqlite3-sysCargo links conflict by usingrusqlitefor SQLite session persistence and limitingsqlxto MySQL/PostgreSQL drivers. - Refactored all executable Rust SQL into a centralized dialect tree at
src/queries/{sqlite,mysql,pgsql}/queries.rs; application modules no longer embed SQL statements. - Added persistent sessions that survive process restarts; SQLite under
data_dir/rustbox.sqliteis the default with no extra configuration. - Added MySQL and PostgreSQL session-database backends plus independently configurable Redis sessions with direct or Sentinel master discovery.
- Added cluster mode validation and shared-session reads so authenticated traffic can move between nodes when a shared SQL/Redis backend is used.
- Encrypts persisted IMAP/SMTP session credentials with AES-256-GCM; single-node SQLite auto-creates
data_dir/session.key, while shared/cluster stores require an explicit common key. - Centralized the complete SQL query catalog by dialect under
src/queries/{sqlite,mysql,pgsql}/queries.rs; session queries use the same tree. Flattened migrations directly undermigrations/{sqlite,mysql,pgsql}/; SQLite user migrations remainV001-V046and sessions useV047__sessions.sqlacross SQL dialects. - Bumped the application/source release to
0.1.0.
0.0.7
- Added
allow-downloadsto the sandboxed HTML message reader so user-initiated downloads are no longer blocked by Chromium sandbox policy. - Added GitHub-, GitLab-, Discord-, Slack-, Reddit- and Notion-inspired predefined interface styles with light/dark palettes.
- Added a release contract that verifies every predefined interface style is visible in the application selector, has a JavaScript profile and CSS palette, and is accepted by backend/config validation.
- Bumped the application/source release to
0.0.7.
0.0.6
- Allowed links in rendered HTML messages to open in a new tab from the sandboxed reader while keeping the opened page outside the message sandbox.
- Added eight predefined color presets: Emerald, Lime, Sky, Navy, Plum, Magenta, Copper, and Sand.
- Bumped the application/source release to
0.0.6.
0.0.5
- Added native file logging through
log_dir; the packaged Linux profile writes JSON logs to/var/log/rustbox/rustbox.logand ships 7-day logrotate policy. - Updated the packaged systemd profile for
/var/lib/rustbox,/var/log/rustbox, hardened service settings, and user-owned configuration. - Fixed the mobile reader toolbar regression so compact controls keep their original height and Message details / Move-copy menus open next to the triggering control instead of at the bottom of the viewport.
- Full-screen message reading now overrides the normal reader width limit so the message workspace uses the available screen width.
- Fixed mobile reader actions, attachment layout, long subjects, and touch targets.
- Added WebSocket application heartbeat, dead-connection detection, exponential reconnect, reconnect resync, event deduplication, and fallback polling.
- Fixed live message refresh coalescing so folder updates cannot suppress a pending new-message refresh.
- Improved new-mail notifications and made notification clicks open the target message when its UID is available.
- Added message full-screen mode from the reader button and context menu with Escape, browser history, deep links, and scroll restoration.
- Kept attachment upload progress only in the composer progress bar and added duplicate/cancellation safeguards.
- Removed source-code comments and added 0.0.5 regression contracts.
- Bumped the application/source release to
0.0.5.
0.0.4
- Changed attachment left-click behavior to prefer in-app preview for supported files while keeping direct download for non-previewable formats.
- Added attachment right-click actions for explicit Preview and Download.
- When an attachment exceeds the preview limit, RustBox now offers to download it instead of stopping at a warning; known oversized files are detected before their contents are fetched for preview.
- Bumped the application/source release to
0.0.4.
0.0.3
-
Fixed reader toolbar dropdowns for Message details and Move/copy by moving popovers out of the horizontally clipped toolbar layer.
-
Added Fastmail-, Apple Mail-, Yahoo Mail- and HEY-inspired styles plus Nord, and an optional per-account unlock for UI scaling on predefined styles.
-
Added separate mail-size controls:
max_attachment_size_mb = 10per uploaded file andmax_message_size_mb = 50for the complete final RFC822/MIME message. The final MIME bytes are checked before SMTP submission, including base64, multipart and OpenPGP overhead; the composer shows an estimated running total. -
Moved the Diagnostics → IMAP reconnect action below capability details so it no longer collides with the status label.
-
Added the RustBox repository link to Settings → About.
-
Defaulted omitted mail endpoints to localhost:993 (IMAP) and localhost:587 (SMTP); TLS verification is skipped automatically only for loopback endpoints unless
tls_verifyis explicitly configured. -
Swapped the compact composer footer groups so the HTML/Text/Markdown selector is on the left and Cancel/Send on the right.
-
Grouped message details and move/copy actions into compact reader-toolbar menus.
-
Improved Polish translations for composer, message toolbar and per-message context menu.
-
Moved composer format selection to the opposite side of Send/Cancel in the compact composer footer.
-
Added server-wide
default_interface_skin(rustbox,gmail,proton,zoho,outlook, etc.) for login and accounts using Global default. -
Fixed mobile modal/settings overflow, transparent dialog strips, calendar toolbar wrapping and narrow-layout sizing.
-
Fixed visual Sieve rule checkbox alignment and stacked its rule controls safely on small screens.
-
Added tap/keyboard expansion for full recipient addresses in the message reader.
-
Added persistent IMAP quota progress above the sidebar IMAP/version footer.
-
Added administrator-configurable
default_theme = "system" | "dark" | "light"for the pre-login/login UI. -
Added Gmail-, Proton-, Zoho- and Outlook-inspired interface profiles plus a Minimal profile.
-
Expanded Polish translations across settings, dialogs, calendar, contacts, filters and common accessibility/title attributes.
-
Bumped the application/source release to
0.0.3.
0.0.2
- Split the monolithic browser application JavaScript into functional modules under
src/web/js/;build.rsnow assembles the JavaScript manifest into the embedded fingerprinted bundle alongside the existing CSS build. - Removed the duplicate
ui/snapshot;src/web/is the only browser UI source and Cargo assembles embedded CSS/JS bundles inOUT_DIR. - Removed the top-level Compact/Balanced/Comfortable/Reading appearance preset cards.
- Expanded Interface style with RustBox (custom), Roundcube Classic, Roundcube Larry, Roundcube Elastic, Clean, Graphite and High contrast.
- Fixed styles no longer overwrite the user's RustBox custom colors/layout values; switching back to RustBox restores the saved manual configuration.
- Fixed interface styles lock palette/geometry controls while leaving Theme, language, date/time formatting and accessibility/user visibility toggles available.
- Added dedicated light/dark palettes for Larry, Clean, Graphite and High contrast while retaining the existing Classic/Elastic compatibility skins.
- Updated UI/build contract tests for the modular JavaScript build and expanded interface-style validation.
- Fixed the 0.0.2 release build regression by centralizing
AppConfig::default()and updating staleAccountSessiontest fixtures for the new session metadata fields. - Updated UI contract tests and visual fixtures after removal of the legacy
ui/directory. - Fixed release-test regressions in OpenPGP fingerprint validation, protected system-folder recognition, nested
base_pathUI routing, and missing SMTP endpoint handling.
0.0.1
- Reworked Roundcube appearance compatibility: dedicated Classic and Elastic interface skins now use upstream-aligned light palettes, dedicated dark variants, exact Classic red/gray selection accents, Elastic cyan/dark tokens, and palette locking so generic RustBox colors cannot bleed into the selected skin.
- Replaced the mobile folder-drawer close affordance with a left-facing SVG back arrow in a dedicated mobile drawer header.
- Added persisted
interface_skindisplay preferences and two schema migrations for skin selection and saved-response format. - Added Roundcube-style saved/canned responses with text/HTML formats, settings CRUD UI and composer insertion; HTML is sanitized before insertion.
- Added static theme-contract tests and browser-rendered visual fixtures for Classic/Elastic light/dark and mobile drawer validation.
- Moved Sieve rule creation/editing into a dedicated wide modal with the existing live “what will happen” preview; Settings now shows the rule list and launches the editor instead of squeezing the full builder into the settings pane.
- Moved identity/signature editing into a separate viewport-safe modal and eliminated the horizontal overflow caused by the two-column Settings layout.
- Added a persistent full-screen composer toggle.
- Collapsed the OpenPGP composer controls into a compact summary row with expandable details, while keeping PGP options hidden when no OpenPGP keyring is configured.
- Kept the signature image/CID flow from the previous UI patch in the packaged sources and synchronized standalone
ui/assets with embeddedsrc/web/. - Moved bulk message actions into a floating overlay so selection mode no longer consumes the message-list grid row or creates horizontal layout spill.
- Hardened narrow reader/message toolbars and composer layout against controls colliding at split-pane widths.
- Reworked composer address/options rows into distinct fields and allowed the formatting toolbar to wrap cleanly.
- Expanded identity signatures/footers with text + HTML editing and image import/paste; imported images are materialized as inline CID draft attachments when composing.
- Completed the OpenPGP roadmap lifecycle with private-key passphrase change. The existing rPGP implementation remains responsible for key parsing, signing, encryption, verification and decryption; GnuPG is used only to re-wrap an existing secret key when changing its passphrase. Passphrases are exchanged over stdin/status-fd and are never stored in the database or command line.
- Added
POST /pgp/keys/{fingerprint}/change-passphraseand a keyring UI action, including an explicit warning before removing passphrase protection. - Added optional
RUSTBOX_PGP_GPG_BINARYoverride for deployments where the GnuPG binary is not namedgpg. - Expanded the visual Sieve builder with dynamically addable conditions and actions. Additional conditions can be chained with nested AND/OR and capability checks now include dynamically added actions.
- Replaced the stale roadmap gap list with a counted functional checklist: 45 functional items remain after this snapshot, with security/integration/acceptance gates tracked separately.
- Fork base: Oxi
7f1507c486b78cf33e54beb701dd460d3bd2bd5d. - Flattened the Rust application to the repository root:
Cargo.toml,src/,migrations/,tests/andexamples/. - Removed the separate Oxi frontend source and all TypeScript/React/Next.js/Node/Bun build requirements.
- Added a RustBox-owned embedded HTML/CSS/vanilla-JavaScript interface with dark/light/system themes.
- Added
dev.sh; ordinarycargo run,cargo testandcargo build --releasenow work from repository root. - Added mail reader/list/compose/search UI and About/Credits with the consumed Oxi revision embedded from
UPSTREAM_BASE. - Added ManageSieve API/editor with STARTTLS, implicit TLS and explicit plaintext opt-in.
- Added native systemd packaging and Cargo-only CI/release build.
- Added Oxi tracking tools that map upstream
backend/...changes into the flat RustBox tree without importing Oxi frontend sources. - Added full-baseline sync review plus selective single-commit backend porting from Oxi.
- Build fix: corrected the embedded SVG raw-string delimiter, imported Figment's
Formattrait forToml::file, and removed an unusedSieveCapabilitiesre-export. - Mail server endpoints are now configuration-owned; the login form only accepts email, password and remember-session preference.
- Fixed Inbox/folder/quota/draft operations to use the connection profile stored in the authenticated session instead of re-reading an optional global IMAP host.
- Added startup validation for
imap_hostto prevent successful Sieve/login state with a non-functional Inbox. - Rebuilt the interface as a compact three-pane webmail layout with embedded SVG icons, HTML compose formatting, threads, folder actions, Sieve filters and appearance preferences.
- Moved browser sources to
src/web/; Cargobuild.rsbundles modular CSS and the executable embeds all UI assets. - Removed gradients and Unicode pseudo-icons from the application interface.
- Added nested-folder indentation, Reply all, accurate IMAP connection state, and RustBox-branded HttpOnly session/browser cookies.
- Added persistent per-user appearance personalization stored in SQLite.
- Added EN/PL language assets embedded in the Rust binary.
- Added theme palette presets (sage/blue/slate/amber/violet/rose/custom) and custom accent color.
- Added font family/size, message row height, pane widths, border radius, contrast and reduced-motion controls.
- Added toggles for avatars, attachment indicators and flags.
- Added message and folder context menus for common webmail actions.
- Added raw-header viewer and clipboard copy.
- Added folder subscribe/unsubscribe UI and context actions for creating subfolders.
- Added identities/signatures settings UI and composer From identity selection.
- Signatures from the selected identity are inserted into the composer.
- Replaced the internal roadmap with the user-approved 0.0.1 plan.
- Added per-account special IMAP folders for Sent/Drafts/Trash/Junk/Archive and wired them into send/delete/archive/junk flows.
- Added IMAP copy, mark-all-read, empty-folder, multi-select and bulk operations.
- Added drag-and-drop message-to-folder moves and previous/next reader navigation with keyboard shortcuts.
- Added advanced and saved search, read/flag operators, user labels/tags and mailbox quota display.
- Expanded composer to HTML/plain/Markdown modes, inline CID images, attachment reminder and a larger formatting toolbar.
- Expanded identities with Reply-To, automatic Bcc, Organization metadata and text/HTML signature behavior.
- Added contact groups and vCard import/export UI.
- Added a capability-aware visual Sieve rule builder plus vacation/autoresponder generation and server validation.
- Added ICS calendar import UI.
- Connected the browser to the existing IMAP IDLE/WebSocket event stream for realtime refresh and desktop notifications.
- Added notification Do Not Disturb hours and persisted per-folder notification preferences.
- Expanded personalization presets and added custom background, panel and text colors in addition to the accent color.
- Added persisted mailbox preferences for page size, date sort, delayed mark-read, threaded/flat reader mode, HTML/plain preference, quote limiting, snippet visibility and remote-image policy.
- Added remote-image prompting with sandboxed message rendering and no-referrer loading.
- Added IMAP capability diagnostics and a settings diagnostics panel for IMAP, ManageSieve and realtime WebSocket state.
- Added multi-account UI for adding, switching and removing accounts in the current browser session.
- Added user-selectable date and 12/24-hour time formats.
- Added server-side validation for message-list page size/sort and mailbox preference values.
- Added
.emlimport into any selected IMAP folder using APPEND, followed by cache invalidation and realtime folder refresh. - Added
List-Unsubscribehandling for safe HTTPS/mailto targets from message headers. - Added in-app full RFC822 source viewer, Message-ID/sender copy actions and folder-properties inspection.
- Raised extractor body limits only on upload endpoints so the documented attachment/vCard/ICS/.eml limits are actually reachable.
- Expanded contacts with phone, job title, address, website and birthday fields.
- Added contact photo upload/remove/display for PNG/JPEG/WebP with byte-signature validation and a 2 MB limit.
- Extended vCard import/export with TEL, TITLE, ADR, URL and BDAY.
- Changed contact persistence from SQLite
INSERT OR REPLACEto conflict-update semantics so editing a contact does not destroy group/photo relations through a row replacement. - Fixed the calendar delete-handler syntax regression found during pre-release static review.
- Added Tantivy index diagnostics and an in-app rebuild from the per-user SQLite cache.
- Added IMAP request-pool reconnect/verification from Diagnostics.
- Added active-session inventory across browsers while the process is running, User-Agent display, individual revoke and revoke-all-others.
- Expanded calendar events with all-day, recurrence RRULE, attendees, organizer, status, reminder, meeting URL and color fields in the UI; added full local ICS export.
- Added direct ICS/vCard import actions for message attachments.
- Expanded contacts to multiple e-mail addresses, phone numbers and postal addresses.
- Added duplicate-contact detection and transactional merge preserving groups, alternate values and contact photos.
- Validated all 28 SQLite migrations from an empty database plus browser JS/JSON/TOML/shell assets.
- Added Month, Week, Day and Agenda calendar views with persistent view selection and event-color markers.
- Hardened contact/calendar/header/source dialogs against viewport overflow and UI scaling.
- Fixed UI scaling so it also changes icon sizing and field/button spacing, and added persistent draggable pane splitters.
- Added reusable action toasts to additional folder, search, calendar and ManageSieve operations.
- Added Spam / Not spam actions in the primary and bulk message toolbars.
- Added safe attachment Open/Download context actions and browser-side Download all as ZIP with UTF-8 filenames.
- Added To/Cc/Bcc autocomplete using contacts and known addresses, including keyboard navigation.
- Added message-list quick actions for read/unread and flag/unflag.
- Hardened message rendering against RustBox-owned icon sprite markup leaking from malformed MIME content.
- Kept the UI free of gradients, TypeScript, React/Next and Node/Bun runtime dependencies.
- Added collapsible hierarchical IMAP folder branches with per-account remembered expansion state and leaf-name rendering.
- Added a keyboard-shortcuts reference dialog and
!shortcut for Spam / Not spam. - Added direct sender actions from the reader header: compose, add contact, copy address, search and create filter.
- Expanded message sorting to date, sender, subject and size in ascending/descending order, available directly from the message-list toolbar and persisted per account.
- Added the
Contacts onlyremote-image policy, which verifies the current sender against the saved address book before allowing external images. - Expanded the visual Sieve builder with a second condition, AND/OR combination and per-condition negation while retaining server-side CHECKSCRIPT validation.
- Added automatic identity selection on reply/forward using To/Cc and Delivered-To/Envelope-To headers before signature insertion.
- Added mailbox quota warning/danger states at 80%/95% usage.
- Added collapsible thread navigation with remembered expansion state.
- Added safe Undo for MOVE-backed message actions when the destination UID can be resolved unambiguously, including reverse-order bulk Undo.
- Added “Select all results” for search bulk actions by materializing the full cached match set on explicit request.
- Hardened thread matching so
Referencesuses complete Message-ID tokens instead of accepting substring collisions. - Moved safe attachment previews into an in-app modal for images, PDFs and text attachments.
- Added composer upload progress and clipboard image paste as CID inline attachments.
- Added draft recovery from both server-side local drafts and an emergency browser snapshot; SMTP failures force a recoverable draft save.
- Changed autosave so it no longer appends a fresh IMAP Drafts message every 1.2 seconds; IMAP snapshots are reserved for deliberate close/failure points until remote draft UID replacement is implemented.
- Expanded keyboard shortcuts with
Ccompose,Vselection mode andXselect/unselect current message. - Replaced runtime browser
confirm()/prompt()flows in the main RustBox UI with reusable application dialogs, including folder/label choices used by message context actions and quick-filter creation. - Added an explicit message selection mode; row checkboxes are hidden/disabled outside that mode and bulk controls remain available while selecting.
- Fixed compact/comfortable density so it changes control, toolbar and dialog sizing independently from UI scale and the user-defined message-row height.
- Added visible toast auto-dismiss countdowns with pause-on-hover/focus behavior.
- Added Compact, Balanced, Comfortable and Reading interface presets that persist through the existing display-preferences API.
- Reworked message printing to use a sandboxed in-page print frame instead of a popup, while preserving sanitized HTML/plain-text message rendering and message metadata.
- Added persisted composer priority and MDN/read-receipt options; outgoing optional headers are shared by SMTP delivery, draft snapshots and the IMAP Sent copy, with mailbox validation before SMTP.
- Added RFC 8058 one-click unsubscribe through a backend HTTPS POST path with no redirects, DNS/IP public-address checks and direct-address TLS connection to reduce SSRF/DNS-rebinding risk.
- Fixed migration registration so the existing V028 contact migration and new V029 draft-send-options migration are both executed; the migration set is now V001–V029.
- Expanded the visual Sieve builder to three conditions with nested AND/OR grouping, two actions, capability-driven action disabling, managed visual-rule ordering, JSON backup/restore and active-script overwrite confirmation.
- Added optional scheduled vacation start/end dates using Sieve
currentdatewithdate+relationalrequirements when the server advertises those extensions. - Added a browser-wide default Spam/Junk destination with a per-account special-folder override; mail actions fall back to IMAP
\Junk/Spam auto-detection when neither resolves. - Added persistent mailbox-level “flagged on top” and per-folder inherit/on/off overrides. Flagged-first ordering is performed in SQLite before pagination.
- Added a subtle red lower-edge marker to flagged message rows without changing the existing star action.
- Replaced the quick-filter folder prompt/raw-editor handoff with a dedicated ManageSieve filter wizard that previews the rule, respects advertised extensions, validates with CHECKSCRIPT, saves directly to the selected script and can activate it.
- Kept an Advanced editor handoff that preloads the visual Sieve builder for users who want to refine the generated rule.
- Added SQLite migration V030 and a folder-preferences API for per-folder list behavior.
- Added aggregate unread counts to the browser title and supported application badges.
- Added
/api/readyalongside liveness/api/health; readiness checks that the local RustBox data directory is accessible without coupling process readiness to account-specific IMAP/SMTP availability. - Made generic application dialogs scroll as a fallback when their content exceeds the browser workspace, while retaining independent scroll regions for structured composer/settings/contact/calendar/source dialogs.
- Fixed inline-image compose preview: uploaded CID images render from the authenticated draft-attachment endpoint while editing, then serialize back to
cid:references for draft persistence and SMTP/IMAP MIME generation. - Removing an inline-image attachment now also removes its matching image node from the composer instead of leaving a broken placeholder.
- Replaced the About-page Runtime row with
Author: @linuxiarz.pl. - Extended the quick-filter wizard with an optional capability-aware “also mark as read” action and an explicit notice that Sieve rules apply to new incoming mail rather than retroactively changing existing messages.
- Changed the About author label to
@linuxiarz.pl. - Fixed action-toast controls so Undo and the close button share one compact control group; clicks no longer propagate between the two actions.
- Preserved the active folder, loaded-page depth, message-list scroll position and active search context across normal refresh/reconnect flows within the browser session.
- Added an explicit offline/reconnecting state and bounded automatic retry for idempotent GET/HEAD requests only; mutating operations are never automatically replayed.
- Added authenticated SMTP connection diagnostics, IMAP custom-keyword capability detection and local synchronization-cache diagnostics with last folder/message sync timestamps.
- Added friendly active-session client names such as
Firefox · Linuxwhile keeping the full User-Agent available as hover detail. - Added client-side highlighting of active search terms in sender, subject and snippet without injecting result text as HTML.
- Fixed the Settings modal grid so the header occupies only its natural height and the sidebar/content area fills the remaining workspace instead of being pushed toward the bottom for short panels such as About.
- Made Settings navigation/content independently scrollable and mobile tabs horizontally scrollable.
- Added inline-image selection/editing in the composer: display width, inline/left/center/right placement and in-app crop/cut with a live preview. Cropping creates a replacement CID attachment; GIF cropping stays disabled to preserve animation.
- Dragged image files now insert as inline CID images in HTML mode instead of silently becoming ordinary attachments.
- Added cleanup of CID attachments whose inline image was removed from the editor, including a final cleanup before send/close.
- Added a warning before switching away from HTML when rich formatting may be lost.
- Added persisted Composing settings for default format, draft autosave interval, default priority, default MDN/read-receipt request and attachment-reminder behavior.
- Added SQLite migration V031 for the new composing preferences.
- Added SQLite migrations V032–V036 for advanced appearance preferences, draft compose-format persistence, optional IMAP-keyword synchronization, composer behavior preferences and remote IMAP-draft tracking.
- Expanded Appearance with icon size, toolbar/sidebar density, reader/composer widths, selection color, unread styling, compact headers, border/scrollbar controls, monochrome mode and per-pane background overrides.
- Completed the safe Markdown compose pipeline: Markdown source remains the plain alternative while preview/delivery uses escaped generated HTML rather than raw Markdown HTML.
- Added persisted composer defaults for font, reply-above/below-quote, quote style, forward inline/as-attachment and browser spellcheck.
- Added administrator-configurable outgoing headers with header-name validation, structural/MIME-header denylisting and CR/LF-injection rejection.
- Added opt-in native IMAP keyword synchronization for RustBox labels. Stable RustBox keywords are written only where persistent custom keywords are supported and observed RustBox keywords are imported back into local labels; full remote-removal reconciliation remains partial.
- Reworked deliberate IMAP Drafts snapshots so RustBox resolves the newly appended draft UID from UIDNEXT plus an exact
X-RustBox-Draft-IDsearch, stores UID/UIDVALIDITY and removes the prior snapshot only after an unambiguous safe match. - Added strict draft-ID validation before attachment-path use, closing traversal through draft identifiers and making the draft marker safe for IMAP headers.
- Changed attachment uploads to stream multipart chunks into bounded
.partfiles with atomic rename, stale-part cleanup and cleanup on interruption/error instead of buffering the entire upload in memory. - Fixed the duplicated draft-route
Extension(config)extractor and kept standaloneui/assets synchronized with embeddedsrc/web/sources. - Fixed the Axum 0.8
E0277 Handlerfailure in tag/bulk-tag routes by separating synchronous SQLite work from awaited IMAP work; no rusqlite connection/transaction is retained across network awaits. - Applied the same DB/network phase separation to single-tag, untag and tag-delete handlers so the compile failure does not simply move to the next route.
- Added authoritative IMAP-label reconciliation for folders that explicitly support persistent custom keywords. Remote RustBox keyword additions and removals can now be reconciled into local labels from Mailbox settings.
- Fixed
Keep me signed inso the server-side session timeout is extended together with the cookie instead of still expiring at the normal default timeout. - Active-session diagnostics now expose effective expiry and whether the session uses the remembered timeout.
- Added graceful SIGTERM/Ctrl+C shutdown and explicit cancellation of dedicated IMAP IDLE tasks before process exit.
- Extended synchronization diagnostics with active IMAP IDLE task/subscriber counts to make reconnect storms and leaked subscriptions visible from the UI.