@bobfrankston/mailx 1.0.147 → 1.0.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,245 +13,355 @@ npm install -g @bobfrankston/mailx
13
13
  mailx
14
14
  ```
15
15
 
16
- Requires Node.js 22 or later (uses built-in `node:sqlite`).
16
+ Requires Node.js 22 or later.
17
17
 
18
- On Windows, the native WebView2 app launches automatically. On Linux/Mac, it opens in your default browser at `http://127.0.0.1:9333`.
18
+ On Windows, the native WebView2 app launches automatically via IPC (no HTTP server needed). Use `mailx --server` for browser mode at `http://127.0.0.1:9333`.
19
19
 
20
20
  ## First-Time Setup
21
21
 
22
- ### Option A: Existing user on a new machine (shared settings on OneDrive)
22
+ On first run, mailx shows a setup form. Enter your name and email address.
23
23
 
24
- If you already have mailx configured on another machine with settings on OneDrive, just install and run. mailx auto-detects shared settings at:
24
+ ### Gmail / Google Workspace
25
25
 
26
- - `%OneDrive%/home/.mailx/settings.jsonc`
27
- - `%OneDriveConsumer%/home/.mailx/settings.jsonc`
28
- - `~/OneDrive/home/.mailx/settings.jsonc`
26
+ No password needed. mailx detects Gmail via MX records, opens a browser for OAuth2 sign-in, and auto-configures Google Drive for settings sync. Custom domains hosted on Google Workspace are detected automatically.
29
27
 
30
- Once OneDrive syncs, mailx picks up your accounts automatically.
28
+ ### Outlook / Hotmail / Live
31
29
 
32
- ### Option B: New user -- single machine, local settings
30
+ No password needed. OAuth2 sign-in opens in your browser.
33
31
 
34
- **Step 1.** Create `~/.mailx/settings.jsonc` with your account(s):
32
+ ### Yahoo
35
33
 
36
- (On Windows `~` means `%USERPROFILE%`, e.g., `C:\Users\You\.mailx\settings.jsonc`)
34
+ Use an **app password** (not your regular password):
35
+ 1. Go to **Yahoo Account Settings** > **Account Security**
36
+ 2. Click **Generate app password**
37
+ 3. Paste the generated password into mailx
37
38
 
38
- **Gmail -- minimal config (just your email):**
39
- ```jsonc
40
- {
41
- "accounts": [
42
- { "email": "you@gmail.com" }
43
- ]
44
- }
45
- ```
39
+ ### AOL
46
40
 
47
- mailx auto-fills Gmail's IMAP/SMTP/OAuth settings. First run opens a browser for OAuth consent.
41
+ Use an **app password**:
42
+ 1. Go to **AOL Account Settings** > **Account Security**
43
+ 2. Click **Generate app password**
44
+ 3. Paste the generated password into mailx
48
45
 
49
- **Standard IMAP -- just host and password:**
50
- ```jsonc
51
- {
52
- "accounts": [
53
- {
54
- "email": "you@example.com",
55
- "password": "your-password",
56
- "imap": { "host": "imap.example.com" },
57
- "smtp": { "host": "smtp.example.com" }
58
- }
59
- ]
60
- }
61
- ```
46
+ ### iCloud
62
47
 
63
- Defaults: port 993/587, TLS on, auth password, username = email address. Only provide fields that differ from defaults.
48
+ Use an **app-specific password**:
49
+ 1. Go to [appleid.apple.com](https://appleid.apple.com) > **Sign-In and Security**
50
+ 2. Click **App-Specific Passwords** > **Generate**
51
+ 3. Paste the generated password into mailx
52
+
53
+ ### Other Providers (Dovecot, Fastmail, etc.)
54
+
55
+ Enter your IMAP password. mailx auto-detects server settings via MX records and DNS. If detection fails, use **Manual setup (advanced)** in the setup form, or create an accounts file and import it (see below).
56
+
57
+ ### Adding Accounts via File
58
+
59
+ You can create an `accounts.jsonc` file and import it into mailx. This is useful for adding accounts that aren't easily configured through the setup form (custom IMAP servers, non-standard ports, etc.).
60
+
61
+ **Step 1.** Create a file (e.g., `my-accounts.jsonc`) with your account(s):
64
62
 
65
- **Full config with all optional fields:**
66
63
  ```jsonc
67
64
  {
68
65
  "accounts": [
69
66
  {
70
- "id": "mymail", // Internal ID (default: domain name)
71
- "name": "Your Name", // From: header name (default: local part of email)
72
- "label": "Work", // UI display label (default: name)
73
67
  "email": "you@example.com",
68
+ "name": "Your Name",
69
+ "label": "Work", // Display name in folder tree
74
70
  "imap": {
75
- "host": "imap.example.com", // Default: imap.{domain}
76
- "port": 993, // Default: 993
77
- "tls": true, // Default: true
78
- "auth": "password", // Default: "password" (or "oauth2" for Gmail/Outlook)
79
- "user": "you@example.com", // Default: email address
71
+ "host": "imap.example.com", // IMAP server hostname
72
+ "port": 993, // 993 for TLS (default)
73
+ "tls": true,
74
+ "user": "you@example.com", // IMAP username (default: email)
80
75
  "password": "your-password"
81
76
  },
82
77
  "smtp": {
83
- "host": "smtp.example.com", // Default: smtp.{domain}
84
- "port": 587, // Default: 587
85
- "tls": true, // Default: true
86
- "auth": "password",
78
+ "host": "smtp.example.com", // SMTP server hostname
79
+ "port": 587, // 587 for STARTTLS (default)
80
+ "tls": true,
87
81
  "user": "you@example.com",
88
82
  "password": "your-password"
89
- },
90
- "enabled": true, // Default: true
91
- "defaultSend": true, // Use this account when From doesn't match
92
- "relayDomains": [], // Domains to skip in Delivered-To chain
93
- "deliveredToPrefix": [] // Prefixes to strip from Delivered-To alias
83
+ }
94
84
  }
95
- ],
96
- "sync": {
97
- "intervalMinutes": 5, // Default: 5
98
- "historyDays": 0 // Default: 30 (0 = all)
99
- },
100
- "ui": {
101
- "theme": "system" // "system" (default), "dark", or "light"
102
- }
85
+ ]
103
86
  }
104
87
  ```
105
88
 
106
- **Known providers with automatic defaults:** Gmail, Google, Outlook, Hotmail, Yahoo, iCloud. For these, only `email` is required.
107
-
108
- No `config.jsonc` needed -- when it doesn't exist, mailx reads settings directly from `~/.mailx/`.
109
-
110
- **Step 2.** Run `mailx` and open `http://127.0.0.1:9333` in your browser.
111
-
112
- ### Option C: Multi-machine with shared settings (OneDrive/Dropbox)
113
-
114
- To share settings across machines, put `settings.jsonc` in a cloud-synced folder and create a local pointer file.
115
-
116
- **Step 1.** Move `settings.jsonc` to a shared location:
117
-
118
- ```
119
- # Example: OneDrive
120
- mkdir "%OneDrive%\home\.mailx"
121
- move "%USERPROFILE%\.mailx\settings.jsonc" "%OneDrive%\home\.mailx\settings.jsonc"
122
- ```
123
-
124
- **Step 2.** Create `~/.mailx/config.jsonc` pointing to the shared location:
89
+ For known providers, most fields are optional:
125
90
 
126
91
  ```jsonc
127
92
  {
128
- // Where the shared settings live (OneDrive, Dropbox, network share, etc.)
129
- "sharedDir": "C:/Users/You/OneDrive/home/.mailx",
130
-
131
- // Local-only settings (not synced):
132
- "storePath": "C:/Users/You/.mailx/mailxstore", // cached message bodies
133
- "historyDays": 90 // override sync depth per machine
93
+ "accounts": [
94
+ { "email": "you@gmail.com", "name": "Your Name" },
95
+ { "email": "you@yahoo.com", "name": "Your Name", "password": "app-password-here" },
96
+ {
97
+ "email": "you@yourserver.com",
98
+ "name": "Your Name",
99
+ "label": "Personal",
100
+ "imap": { "host": "imap.yourserver.com", "user": "you", "password": "pass" },
101
+ "smtp": { "host": "smtp.yourserver.com", "user": "you", "password": "pass" }
102
+ }
103
+ ]
134
104
  }
135
105
  ```
136
106
 
137
- **How it works:**
138
- - `config.jsonc` is local to each machine -- never synced
139
- - `sharedDir` points to the cloud folder containing `settings.jsonc`, `allowlist.jsonc`, `preferences.jsonc`
140
- - mailx caches shared files locally for offline use
141
- - `historyDays` in `config.jsonc` overrides the shared default per machine
142
- - On new machines, if `config.jsonc` doesn't exist, mailx auto-detects OneDrive at `%OneDrive%/home/.mailx/`
107
+ **Step 2.** Import into mailx:
143
108
 
144
- ### Gmail OAuth setup
109
+ ```bash
110
+ mailx --import my-accounts.jsonc
111
+ ```
112
+
113
+ This merges the accounts into your Google Drive settings (deduplicates by email address). Existing accounts are preserved.
145
114
 
146
- Gmail accounts auto-configure -- just add `{ "email": "you@gmail.com" }` to accounts. But OAuth requires a one-time Google Cloud setup:
115
+ ### Gmail OAuth Prerequisites
147
116
 
117
+ Gmail OAuth requires a one-time Google Cloud setup:
148
118
  1. Go to [Google Cloud Console](https://console.cloud.google.com/) and create a project
149
119
  2. Enable the **Gmail API** (and **People API** for contacts)
150
120
  3. Create **OAuth 2.0 credentials** (Desktop app type)
151
121
  4. Download `credentials.json` to the iflow package directory
152
- 5. First connection opens a browser for OAuth consent. Tokens are cached and refresh automatically.
122
+ 5. First connection opens a browser for consent. Tokens refresh automatically.
153
123
 
154
124
  ## Usage
155
125
 
156
126
  ### Reading Mail
157
- - **Folder tree** (left) -- click to view, expand/collapse subfolders
158
- - **Message list** (center) -- click to preview, scroll for more
159
- - **Preview pane** (right) -- shows message content
160
- - **All Inboxes** -- unified view across all accounts
161
- - **Folder search** -- filter box above folder tree to find folders quickly
162
- - **Message search** -- search bar with scope: This folder / All folders / IMAP server
127
+
128
+ - Click a **folder** to see its messages
129
+ - Click a **message** to read it in the preview pane
130
+ - **All Inboxes** combines inboxes from all accounts (appears with 2+ accounts)
131
+ - Unread counts show on folders; sub-folder counts bubble up to collapsed parents
132
+ - Use the **folder search** box to find folders by name
163
133
 
164
134
  ### Composing
165
- - **Compose** -- toolbar or Ctrl+N
166
- - **Reply / Reply All / Forward** -- Ctrl+R / Ctrl+Shift+R / toolbar
167
- - **Send** -- Ctrl+Enter
168
- - **From field** -- dropdown with all accounts + "Other..." for custom addresses
169
- - **Address autocomplete** -- type in To/Cc/Bcc, Tab accepts match
170
- - **Auto-save** -- drafts saved to IMAP every 5 seconds
135
+
136
+ - **Ctrl+N** -- New message
137
+ - **Ctrl+R** -- Reply
138
+ - **Ctrl+Shift+R** -- Reply All
139
+ - **Ctrl+F** -- Forward
140
+ - From dropdown lets you pick which account to send from
141
+ - Contact autocomplete searches Google Contacts as you type in To/Cc/Bcc
142
+ - Drafts auto-save every 5 seconds to your Drafts folder
171
143
 
172
144
  ### Managing Messages
173
- - **Delete** -- Del key or trash button, moves to Trash. Ctrl+Z to undo (30s).
174
- - **Flag/unflag** -- click the star
175
- - **Drag and drop** -- drag messages to folders to move them. Shift/Ctrl+click for multi-select.
176
- - **Attachments** -- click the chip to open PDFs, images, etc. in the browser
177
- - **Remote content** -- blocked by default. "Load once" or "Always" buttons on the banner.
178
- - **Unsubscribe** -- button appears in header when List-Unsubscribe header is present
179
- - **View Source** -- Source button copies .eml file path to clipboard
180
- - **Link preview** -- hover over links in email body to see URL in status bar
181
-
182
- ### Managing Folders
183
- - **Right-click any folder** for context menu:
184
- - Mark all read
185
- - New subfolder
186
- - Rename folder
187
- - Delete folder
188
- - Empty folder (Trash/Junk only -- permanently deletes all messages)
189
- - Special folders (Inbox, Sent, Trash, etc.) cannot be renamed or deleted
145
+
146
+ - **Delete** or **Ctrl+D** -- Delete selected messages (moves to Trash)
147
+ - **Ctrl+Z** -- Undo last delete
148
+ - **Ctrl+A** -- Select all messages in the list
149
+ - **Drag and drop** -- Move messages to a folder by dragging them
150
+ - Click the **star** column to flag/unflag a message
151
+ - **Unsubscribe** button appears when the message has a List-Unsubscribe header
152
+
153
+ ### Searching
154
+
155
+ Type in the search bar and press **Enter**. Use the dropdown to search:
156
+ - **All folders** -- Every account and folder
157
+ - **This folder** -- Current folder only (filters as you type, server search on Enter)
158
+ - **IMAP server** -- Server-side search (useful for messages older than your sync window)
159
+
160
+ Supports regex: wrap pattern in `/slashes/`.
161
+
162
+ ### Folder Operations
163
+
164
+ Right-click a folder for options:
165
+ - Mark all read
166
+ - New subfolder
167
+ - Rename / Delete folder
168
+ - Empty (Trash and Junk only)
169
+
170
+ ### View Options
171
+
172
+ Under **View** in the toolbar:
173
+ - **Two-line view** -- Show preview snippet below each subject
174
+ - **Preview pane** -- Toggle the message reader panel
175
+ - **Preview snippets** -- Show snippet text in message rows
176
+ - **Flagged only** -- Show only starred messages
177
+ - **Folder counts** -- Show total message counts on all folders
178
+
179
+ ### Settings
180
+
181
+ Under **Settings** in the toolbar:
182
+ - **Editor** -- Choose between Quill (default) and tiptap for compose
183
+ - **AI autocomplete** -- Enable LLM-powered writing suggestions (Ollama, Claude, or OpenAI)
190
184
 
191
185
  ### Keyboard Shortcuts
186
+
192
187
  | Key | Action |
193
188
  |-----|--------|
194
189
  | Ctrl+N | New message |
195
190
  | Ctrl+R | Reply |
196
191
  | Ctrl+Shift+R | Reply All |
197
- | Del / Ctrl+D | Delete |
192
+ | Ctrl+F | Forward |
193
+ | Delete / Ctrl+D | Delete |
198
194
  | Ctrl+Z | Undo delete |
199
- | Ctrl+Enter | Send (compose) |
200
- | Escape | Clear search / Discard compose |
195
+ | Ctrl+A | Select all |
201
196
  | F5 | Sync all folders |
197
+ | Escape | Clear search / close menus |
202
198
 
203
- ### View Options (View menu)
204
- - **Two-line view** -- compact message rows
205
- - **Preview pane** -- toggle on/off
206
- - **Flagged only** -- show only starred messages
199
+ ## Command Line
207
200
 
208
- ## Data Storage
201
+ ```
202
+ mailx Start the app (native window via IPC)
203
+ mailx --server Start HTTP server mode (http://localhost:9333)
204
+ mailx --no-browser Server mode without opening browser
205
+ mailx --verbose Show log output in terminal (default: log file only)
206
+ mailx --import <file> Import accounts.jsonc into Google Drive
207
+
208
+ mailx -kill Kill running mailx processes + clean up WAL files
209
+ mailx -repair Re-sync message metadata (fix garbled subjects)
210
+ mailx -rebuild Wipe local cache and re-download everything from IMAP
211
+ mailx -setup Interactive first-time setup (CLI)
212
+ mailx -test Test IMAP/SMTP connectivity for all accounts
213
+ mailx -v Show version
214
+ ```
215
+
216
+ ### -repair vs -rebuild
217
+
218
+ **-repair** clears message metadata (subjects, flags, sender names) from the database but preserves your downloaded `.eml` message files. Folder sync state resets so mailx re-fetches all envelopes on next run. Use this when subjects show garbled characters.
219
+
220
+ **-rebuild** deletes the entire database and message store, then re-downloads everything from IMAP. Accounts and settings are preserved. Use this for a clean start or to reclaim disk space.
209
221
 
210
- All data lives in `~/.mailx/` (e.g., `C:\Users\You\.mailx\`):
222
+ ## Configuration
211
223
 
212
- | File | Shared? | Purpose |
224
+ All config files live in `~/.mailx/` (on Windows: `C:\Users\You\.mailx\`).
225
+
226
+ ### config.jsonc (per-machine, not synced)
227
+
228
+ Points to shared settings and controls local behavior. Created automatically for Gmail accounts.
229
+
230
+ ```jsonc
231
+ {
232
+ "sharedDir": { "provider": "gdrive", "path": "mailx", "folderId": "..." },
233
+ "storePath": "C:/Users/You/.mailx/mailxstore",
234
+ "historyDays": 90,
235
+ "accountOverrides": {
236
+ "work": { "historyDays": 7 },
237
+ "archive": { "enabled": false }
238
+ }
239
+ }
240
+ ```
241
+
242
+ **sharedDir** can be:
243
+ - `{ "provider": "gdrive", "path": "mailx" }` -- Google Drive via API (auto-configured for Gmail)
244
+ - `"C:/Users/You/OneDrive/home/.mailx"` -- Local/network path
245
+
246
+ ### accounts.jsonc (shared via Google Drive or local)
247
+
248
+ For known providers, only `email` is required -- IMAP/SMTP settings fill automatically.
249
+
250
+ ```jsonc
251
+ {
252
+ "accounts": [
253
+ { "email": "you@gmail.com", "name": "Your Name" },
254
+ { "email": "you@icloud.com", "name": "Your Name", "password": "xxxx-xxxx-xxxx-xxxx" },
255
+ {
256
+ "email": "you@example.com",
257
+ "name": "Your Name",
258
+ "label": "Work",
259
+ "imap": { "host": "imap.example.com", "port": 993, "tls": true, "user": "you", "password": "..." },
260
+ "smtp": { "host": "smtp.example.com", "port": 587, "tls": true, "user": "you", "password": "..." }
261
+ }
262
+ ]
263
+ }
264
+ ```
265
+
266
+ **Auto-detected providers:**
267
+
268
+ | Domain | IMAP | SMTP | Auth | Label |
269
+ |--------|------|------|------|-------|
270
+ | gmail.com | imap.gmail.com:993 | smtp.gmail.com:587 | OAuth2 | Gmail |
271
+ | outlook.com, hotmail.com | outlook.office365.com:993 | smtp.office365.com:587 | OAuth2 | Outlook |
272
+ | yahoo.com | imap.mail.yahoo.com:993 | smtp.mail.yahoo.com:587 | App password | Yahoo |
273
+ | aol.com | imap.aol.com:993 | smtp.aol.com:587 | App password | AOL |
274
+ | icloud.com | imap.mail.me.com:993 | smtp.mail.me.com:587 | App password | iCloud |
275
+
276
+ Google Workspace and Microsoft 365 custom domains are detected automatically via MX records.
277
+
278
+ ### preferences.jsonc (shared)
279
+
280
+ ```jsonc
281
+ {
282
+ "ui": { "theme": "dark", "editor": "quill", "fontSize": 15 },
283
+ "sync": { "intervalMinutes": 5, "historyDays": 30 },
284
+ "autocomplete": {
285
+ "enabled": false,
286
+ "provider": "ollama",
287
+ "ollamaUrl": "http://localhost:11434",
288
+ "ollamaModel": "qwen2.5-coder:1.5b"
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### allowlist.jsonc (shared)
294
+
295
+ Remote content (images, tracking pixels) is blocked by default. Whitelist trusted senders:
296
+
297
+ ```jsonc
298
+ {
299
+ "senders": ["boss@example.com"],
300
+ "domains": ["example.com"],
301
+ "recipients": ["team@our-group.com"]
302
+ }
303
+ ```
304
+
305
+ ### Multi-Machine Setup
306
+
307
+ Settings sync via Google Drive API. Each machine has its own `config.jsonc`:
308
+
309
+ **Desktop** (full history):
310
+ ```jsonc
311
+ { "sharedDir": { "provider": "gdrive", "path": "mailx" }, "historyDays": 0 }
312
+ ```
313
+
314
+ **Laptop** (recent only):
315
+ ```jsonc
316
+ { "sharedDir": { "provider": "gdrive", "path": "mailx" }, "historyDays": 30,
317
+ "accountOverrides": { "archive": { "enabled": false } } }
318
+ ```
319
+
320
+ Both machines share accounts, preferences, and allowlist via Google Drive.
321
+
322
+ ## Data Storage
323
+
324
+ | Path | Synced? | Purpose |
213
325
  |------|---------|---------|
214
- | config.jsonc | No | Points to shared settings + local overrides |
215
- | settings.jsonc | Yes | Account configs, sync, UI prefs (or split files below) |
326
+ | config.jsonc | No | Local config pointer + overrides |
216
327
  | accounts.jsonc | Yes | IMAP/SMTP account configs |
217
328
  | preferences.jsonc | Yes | UI and sync settings |
218
- | allowlist.jsonc | Yes | Remote content sender/domain allow-list |
329
+ | allowlist.jsonc | Yes | Remote content allow-list |
219
330
  | mailx.db | No | SQLite metadata (headers, contacts, sync state) |
220
331
  | mailxstore/ | No | Cached message bodies (.eml per message) |
221
- | logs/ | No | Server logs (auto-deleted after 7 days) |
222
- | window.json | No | Window position (per machine) |
223
- | webview2/ | No | WebView2 data (Windows native app) |
332
+ | logs/ | No | Daily log files |
224
333
 
225
- **Shared** files can live on OneDrive/Dropbox. **Local** files stay on the machine.
334
+ **Safe to delete:** mailxstore/ (re-downloaded on sync), mailx.db (re-created on startup), logs/ (anytime).
226
335
 
227
- ### Safe to Delete
336
+ ## Logs
228
337
 
229
- - **mailxstore/** -- re-downloaded during sync. Delete to reclaim space.
230
- - **mailx.db** -- re-created on startup, triggers full re-sync.
231
- - **logs/** -- safe to delete anytime.
232
- - **window.json** -- resets window position.
338
+ Daily log files: `~/.mailx/logs/mailx-YYYY-MM-DD.log`
233
339
 
234
- ## Development
340
+ Use `mailx --verbose` to see logs in the terminal instead.
235
341
 
236
- ```bash
237
- git clone https://github.com/BobFrankston/mailx.git
238
- cd mailx
239
- npm install
240
- npm start # Server with --watch (auto-restart)
241
- # Open http://127.0.0.1:9333
242
-
243
- launch.ps1 # Windows native WebView2 app
244
- launch.ps1 -restart # Kill existing and restart
245
- launch.ps1 -clear # Clear WebView2 cache
246
- ```
342
+ ## Troubleshooting
343
+
344
+ **Blank window or no response** -- Run `mailx -kill` then `mailx` to restart.
345
+
346
+ **OAuth timeout** -- If the browser auth window doesn't appear or times out (5 minutes), close mailx and try again.
347
+
348
+ **Garbled subjects** -- Run `mailx -repair` to re-sync metadata from IMAP.
349
+
350
+ **Sync stuck or corrupt data** -- Run `mailx -rebuild` for a clean start. Accounts and settings are preserved.
351
+
352
+ **"Too many connections"** -- mailx uses up to 5 IMAP connections per account. Close other email clients if you hit your server's limit.
353
+
354
+ **App password rejected (Yahoo/AOL/iCloud)** -- Make sure you're using an app-specific password, not your regular login. Generate a new one from your account security settings.
247
355
 
248
356
  ## Architecture
249
357
 
250
- - **Local-first** -- changes update local DB immediately, background worker syncs to IMAP
251
- - **Offline reading** -- full message bodies cached as .eml files during sync
252
- - **IMAP IDLE** -- instant new mail notifications + periodic sync fallback
253
- - **Outbox** -- queued in IMAP Outbox folder with multi-machine interlock via flags
254
- - **Remote content blocking** -- HTML sanitized server-side, CSP in iframe, per-sender/domain allow-list
255
- - **Search** -- SQLite FTS5 full-text index, IMAP server search, regex filtering
256
- - **Built-in SQLite** -- uses Node.js built-in node:sqlite (no native compilation needed)
257
- - **Cross-platform** -- Windows (WebView2), Linux (webkit2gtk), any platform (browser mode)
358
+ - **IPC-first** -- Default mode uses msger (Rust/WebView2) with bidirectional IPC. No TCP server, no CLOSE_WAIT zombies.
359
+ - **HTTP fallback** -- `--server` flag starts Express for browser/remote access.
360
+ - **Local-first** -- Changes update local DB immediately; background worker syncs to IMAP.
361
+ - **Offline reading** -- Full message bodies cached as .eml files.
362
+ - **IMAP IDLE** -- Instant new-mail notifications + periodic sync fallback.
363
+ - **Outbox** -- Queued in IMAP Outbox folder with multi-machine interlock via flags.
364
+ - **Remote content blocking** -- HTML sanitized server-side, CSP in iframe, per-sender allow-list.
365
+ - **Search** -- SQLite FTS5 full-text index + IMAP server search + regex filtering.
366
+ - **Connection management** -- Semaphore limits 5 connections per account; exponential backoff on server limits.
367
+ - **Cloud sync** -- Google Drive API for settings portability (no filesystem mount required).