RustBox 0.2.22 release manifest 0.2.22 release changes: - adds message snooze: snoozing a message hides it client-side from its folder's current view until the chosen wake time, without touching server-side folder pagination/count SQL; `snoozed_messages` is a local-only cache table with no IMAP side effects, so a snoozed message is unaffected on any other client - adds an "Undo Send" window: when `undo_send_window_secs > 0` (default 8s, max 120s), a submitted message is held in memory and only dispatched to SMTP after the window elapses unless cancelled; nothing is persisted, so a server restart during the window loses the staged send the same way an in-flight SMTP connection would be lost - adds `GET/DELETE /messages/send/{pending_send_id}` to poll or cancel a staged send, and `POST/DELETE /messages/{folder}/{uid}/snooze`, `GET /messages/snoozed`, `GET /folders/{name}/snoozed-uids` for snooze 0.2.21 release changes and retained feature set: - 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) - fixes the Axum route visibility mismatch for `AttachMessageSourceRequest`, allowing the forward-as-attachment handler to compile from `routes::mod` - falls back to IMAP `INTERNALDATE` for messages with a missing/invalid message `Date` and repairs cached missing dates when opening a folder - forwards a message as a real server-created `message/rfc822` `.eml` draft attachment - expands sandboxed HTML message previews to the real remaining reader height and keeps that height synchronized across layout/fullscreen changes - adds equal-height text/HTML signature fields and a dedicated raw-HTML + visual signature editor with image insertion - keeps synchronization activity visible during page/progressive/all mailbox loads and individual message retrieval - adds Shift-click contiguous message selection and direct first/last pagination controls - fixes HTML signature formatting so toolbar actions preserve the selected text and reliably toggle formatting - gives new messages with visible signatures a real editable body entry above the signature and softens/spaces the composer-only separator - strips the editor-only body-entry marker from serialized outgoing HTML while retaining signature de-duplication metadata - defaults wide message panes to compact single-line rows, with an Appearance setting to disable the behavior - adds per-identity signature insertion mode: silent append-on-send (default) or visible/editable in the composer - adds a durable SQL blob-deletion outbox used by filesystem/shared POSIX/NFS and S3 backends; attachment/draft cleanup is transactionally queued and retried until successful - failed finalized uploads and failed destination objects from storage migration are also queued for cleanup; storage health probes reuse a fixed key to avoid unbounded probe-object buildup - suppresses realtime “new message” toast/system notifications for Drafts saves while preserving normal folder/list refresh and `\Draft` + `\Seen` IMAP flags - adds `Delete draft` in the composer; IMAP deletion is UID/UIDVALIDITY-checked and local draft attachment rows/blobs are cascaded after the server draft is removed - adds an explicit `Save draft` action before `Cancel`; it persists the current message and attachments as a real IMAP Drafts snapshot without changing background autosave behavior - explicit IMAP draft saves surface snapshot/APPEND failures instead of reporting a false success - draft recovery restores attachment metadata from browser snapshots plus the authoritative server draft - attachment chips show all uploaded files, including inline images/links, and new uploads merge by unique attachment ID instead of replacing visible entries - fixes multi-attachment/inline-image insertion so new items append instead of replacing the selected image/content - uses DOM Range insertion with stable caret placement for embedded images and CID file links - floats image sizing/alignment actions over the editor instead of consuming composer height - supports Ctrl/Cmd+V image embedding, file drop at the caret, dragging embedded images within the body, and four resize handles - labels embedded images separately from regular/image attachment chips - keeps attachment re-embed actions compact and allows separate same-name/same-size files - compact recipient address summaries with expandable full recipient lists - adds default pagination at 300 messages per page, plus optional smooth progressive loading and full-folder loading - adds a composer `Hide fields` / `Show fields` control so From/To/Cc/Bcc/Subject/options can collapse and the editor can use the freed vertical space - inline-by-default image attachments, re-embedding, CID file links, and inline image layout controls - opens message-body links without an explicit target in a new tab/window instead of navigating inside the sandboxed mail-preview iframe; explicit targets remain intact - shows the login success toast only after a real POST login; session restoration/page refresh is silent - improves non-ASCII/Polish mail display with explicit UTF-8 preview documents and broader RFC 2047 header decoding (including ISO-8859-2/Windows-1250) - previews PDFs from the authenticated inline attachment endpoint instead of a blob iframe for Safari/iPhone compatibility - presents compose attachment/message size limits as compact raw values without implementation-detail descriptions - retains the 0.2.9 realtime notification, shortcut and 300-message mailbox behavior - adds opt-in adaptive HTML-mail colors in Appearance plus mailbox loading-mode selection, persisted by runtime migration V051 Architecture: - database_backend = sqlite | mysql | pgsql selects authoritative SQL only - blob storage and search are independent from the SQL engine - PostgreSQL/MySQL single-node deployments may continue to use data_dir-backed filesystem/Tantivy - cluster mode clears an implicit/default data_dir; explicit data_dir is not forbidden, but local-only capabilities are rejected Blob storage: - filesystem: local single-node or shared POSIX with storage.shared=true - shared POSIX examples: NFS, CephFS, GlusterFS - s3: AWS S3 and S3-compatible endpoints such as MinIO/Ceph RGW - attachment rows use logical storage keys and SHA-256 metadata - storage migration command: rustbox storage migrate --from filesystem:/path --to configured [--dry-run] [--verify] Search: - local_tantivy: single-node only - opensearch: cluster-capable external index - disabled: no full-text index - OpenSearch operations are tenant-scoped by user_hash - durable SQL outbox provides claim/lease, retry/backoff and dead-letter handling - rebuild command: rustbox search reindex Database/schema: - migrations/{sqlite,mysql,pgsql}/schema.sql contain the current fresh schema - compatibility baseline is V050; former V047-V050 changes are consolidated into `schema.sql` and their standalone migrations are removed - databases older than V050 must be upgraded with a V050-capable RustBox release before using this build - V051 adds `display_preferences.adaptive_email_colors` and `mail_preferences.message_loading_mode` to existing V050 tenants - V052 adds `snoozed_messages` (local-only cache state, no IMAP side effects) to existing V051 tenants - next migration number: V053 Docker examples: - docker/compose-single-sqlite.yml - docker/compose-ha-garage.yml (2x RustBox + Envoy + Valkey + PostgreSQL + OpenSearch + Garage S3) - docker/compose-postgres-s3-opensearch.yml (PostgreSQL + SILO/S3 + OpenSearch) - docker/compose-mysql-nfs-opensearch.yml (MySQL + real NFS volume + OpenSearch) Operations/docs: - standalone `scripts/migrate_roundcube.py` imports Roundcube contacts/identities using RustBox config.toml and supports SQLite/MySQL/PostgreSQL targets - README.md documents 0.2.22 configuration - docker/README.md documents Compose variants - docs/STORAGE_SEARCH_OPERATIONS.md documents failure modes, shared-storage requirements and migration behavior - TODO.md leaves live SILO/MinIO/AWS/Ceph and real multi-node acceptance validation explicitly pending Build/release metadata: - `scripts/package-release.sh` runs the full Rust release gate before creating ZIP/SHA256 artifacts - Cargo.toml version = 0.2.22 - rust-toolchain.toml pins Rust 1.99.1 - Cargo.lock is retained for reproducible application builds; the release gate generates it only when missing - CI and scripts/build-release.sh use the retained Cargo.lock (generating it only if missing), then run locked tests/Clippy/release build