State Management & Caching
Relevant source files
The following files were used as context for generating this wiki page:
Mailiner manages application state through a combination of in-memory signals, persistent browser storage, and specialized caches. The system prioritizes privacy and performance by keeping all sensitive data, such as IMAP credentials and cached mail, within the local browser environment.
The architecture separates long-term configuration (account settings) from ephemeral session data (connection states) and performance-oriented caches (mail headers and UI layout). This ensures the application remains snappy through techniques like pre-fetching and Least Recently Used (LRU) eviction.
Sources: README.md, AGENTS.md, crates/mailiner-app/src/mail_cache.rs:1-15
Persistent Mail Caching
Mailiner uses a local cache to store mailbox trees and message-list prefixes. This allows for an "instant first paint" of the UI before the IMAP connection is established or synchronized. The cache is abstracted via the MailCache trait, allowing the browser to use localStorage while unit tests utilize in-memory storage.
Mail Cache Architecture
The cache stores data in a versioned JSON blob. It enforces strict limits to ensure localStorage remains within browser-defined size constraints.
This diagram shows the relationship between the persistence traits and the physical storage structure in the browser.
Sources: crates/mailiner-app/src/mail_cache.rs:18-50, crates/mailiner-app/src/mail_cache.rs:340-360
Cache Constraints and Eviction
To manage memory and storage limits, the system employs several caps and an LRU (Least Recently Used) eviction policy.
| Constant | Value | Description |
|---|---|---|
MAX_CACHED_FOLDERS | 8 | Max message-list snapshots retained per account. |
MAX_MESSAGES_PER_FOLDER | 50 | Max contiguous prefix envelopes stored per folder. |
MAX_CACHE_BLOB_BYTES | 1,500,000 | Soft cap on the encoded JSON blob (approx 1.5MB). |
MAIL_CACHE_SCHEMA_VERSION | 1 | Schema version to prevent incompatible data loads. |
Sources: crates/mailiner-app/src/mail_cache.rs:19-27
When the JSON blob exceeds the MAX_CACHE_BLOB_BYTES limit during a save operation, the system repeatedly evicts the globally oldest message-list snapshot until the data fits within the budget.
Sources: crates/mailiner-app/src/mail_cache.rs:460-485, crates/mailiner-app/src/mail_cache.rs:414-432
Account and Connection State
Account management involves persisting credentials and tracking the live status of IMAP/SMTP connections.
Account Persistence
Account settings, including IMAP passwords and proxy tokens, are stored exclusively in localStorage. Mailiner does not have a central server account; therefore, clearing site data removes all secrets.
Sources: README.md, crates/mailiner-app/src/components/accounts.rs:114-120
Connection State Lifecycle
The ConnectionState enum tracks the lifecycle of an account's connection to the mail server.
This diagram illustrates the transitions between different connection phases for an email account.
Sources: crates/mailiner-app/src/components/accounts.rs:150-160, crates/mailiner-imap-connector/src/lib.rs:75-100
IMAP Connector Caching
The ImapConnector maintains internal caches to optimize data retrieval and reduce redundant network traffic.
- Structure Cache: A side-cache of
BODYSTRUCTUREconverted toBodyPartobjects, keyed by Folder ID and Message ID. It retains up to 500 entries before performing simple eviction. - List Index: Caches the result of
UID SEARCHorUID SORToperations. This index tracks the total message count and unread count for the currently selected folder. It is rebuilt if the server'sEXISTScount changes.
Sources: crates/mailiner-imap-connector/src/lib.rs:114-120, crates/mailiner-imap-connector/src/lib.rs:565-575, crates/mailiner-imap-connector/src/lib.rs:125-135
UI Layout and Content State
The application state also encompasses the visual configuration of the interface and the transient state of downloads or message formatting.
Layout Persistence
User-defined pane sizes are persisted to localStorage and applied as CSS variables on the root #app element. This ensures the UI layout is preserved across browser refreshes.
Sources: crates/mailiner-app/src/layout.rs:1-15, crates/mailiner-app/src/layout.rs:65-100
Streaming Download State
For large attachments, Mailiner uses a streaming architecture to prevent excessive memory consumption. The StreamingBlobDownload struct accumulates decoded octets as discrete Blob parts.
This sequence shows how data flows from the network into the browser's download manager without buffering the entire file in Rust memory.
Sources: crates/mailiner-app/src/download.rs:70-120
Formatting and Sanitization
The MessageFormatter manages the state of message viewing. It identifies which message parts to display (preferring HTML over Plain Text) and tracks whether remote resources were blocked to preserve user privacy.
Sources: crates/mailiner-app/src/formatter/mod.rs:25-50
Summary
State management in Mailiner is decentralized and privacy-focused. Persistent data like account configurations and mail headers are stored in versioned, size-constrained JSON blobs within browser localStorage. Volatile session state, such as IMAP connection status and partial download buffers, is managed in-memory with clear transitions and cleanup logic. This tiered approach allows the application to function as a full-featured client while remaining within the technical constraints of the WASM/browser environment.
Sources: README.md, crates/mailiner-app/src/mail_cache.rs:1-30