@bobfrankston/rmfmail 1.1.129 → 1.1.130
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/.commitmsg +16 -0
- package/README.md +69 -12
- package/bin/mailx.js +112 -17
- package/bin/mailx.js.map +1 -1
- package/bin/mailx.ts +114 -17
- package/client/app.bundle.js +11 -7
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +22 -1
- package/client/app.js.map +1 -1
- package/client/app.ts +21 -1
- package/client/components/message-viewer.js +5 -10
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +5 -10
- package/package.json +1 -1
- package/packages/mailx-imap/index.d.ts +15 -0
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +102 -0
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +84 -0
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-21308 → node_modules.npmglobalize-stash-40492}/.package-lock.json +0 -0
package/.commitmsg
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
feat: -send <file> CLI + general-outbox auto-routing; draft UI fixes
|
|
2
|
+
|
|
3
|
+
- rmfmail -send <file> [-account <id>]: enqueue a .ltr/.eml from disk for
|
|
4
|
+
sending. With -account, drops into outbox/<id>/; without, drops into the
|
|
5
|
+
general ~/.rmfmail/outbox/ and the daemon's outbox sweep auto-routes by
|
|
6
|
+
parsing the file's From: header (exact match → known-provider domain →
|
|
7
|
+
first non-known-provider "override" account). Bcc preserved as-is;
|
|
8
|
+
existing SMTP/IMAP-Outbox paths handle the strip.
|
|
9
|
+
- Draft UI: clicking a Drafts row no longer auto-pops compose — the
|
|
10
|
+
existing "Edit Draft" button (and double-click) are the only entry
|
|
11
|
+
points. On Send, the draft row drops from the list immediately (was a
|
|
12
|
+
2 s debounce). New "Sent HH:MM" / "Send failed: …" status confirmation.
|
|
13
|
+
- CLI: -send / -account added to knownFlags. Top-of-file Usage comment and
|
|
14
|
+
unknown-flag error string rewritten to be complete and consistent —
|
|
15
|
+
single-dash is canonical, double-dash still accepted as a synonym.
|
|
16
|
+
README "Command Line" section refreshed in lockstep.
|
package/README.md
CHANGED
|
@@ -246,22 +246,79 @@ All AI features are opt-in. Provider + API key live in the autocomplete settings
|
|
|
246
246
|
|
|
247
247
|
## Command Line
|
|
248
248
|
|
|
249
|
+
Flag style: single-dash is canonical (`-kill`, `-setup`, ...). The parser
|
|
250
|
+
also accepts double-dash (`--kill`, `--setup`) as a synonym, so older
|
|
251
|
+
scripts that used `--server` / `--email` keep working.
|
|
252
|
+
|
|
249
253
|
```
|
|
250
254
|
rmfmail Start the app (native window via IPC)
|
|
251
|
-
rmfmail
|
|
252
|
-
rmfmail
|
|
253
|
-
rmfmail
|
|
254
|
-
rmfmail
|
|
255
|
-
|
|
256
|
-
rmfmail -kill
|
|
257
|
-
rmfmail -repair
|
|
258
|
-
rmfmail -rebuild
|
|
259
|
-
rmfmail -setup
|
|
260
|
-
rmfmail -test
|
|
261
|
-
rmfmail -reauth
|
|
262
|
-
rmfmail -v
|
|
255
|
+
rmfmail -email <addr> First-time setup with this email (skips prompt)
|
|
256
|
+
rmfmail -verbose Show log output in terminal (default: log file only)
|
|
257
|
+
rmfmail -import <file> Import accounts.jsonc into Google Drive
|
|
258
|
+
rmfmail -server Start HTTP server for dev/remote (http://localhost:9333)
|
|
259
|
+
|
|
260
|
+
rmfmail -kill Kill running rmfmail processes + clean up WAL files
|
|
261
|
+
rmfmail -repair Re-sync message metadata (fix garbled subjects)
|
|
262
|
+
rmfmail -rebuild Wipe local cache and re-download everything from IMAP
|
|
263
|
+
rmfmail -setup Interactive first-time setup (CLI)
|
|
264
|
+
rmfmail -test Test IMAP/SMTP connectivity for all accounts
|
|
265
|
+
rmfmail -reauth Clear cached OAuth tokens; next start re-consents
|
|
266
|
+
rmfmail -v Show version
|
|
267
|
+
|
|
268
|
+
rmfmail -send <file> Enqueue a .ltr/.eml for sending. Daemon parses
|
|
269
|
+
the file's From: header to auto-route to a
|
|
270
|
+
configured account; falls back to the first
|
|
271
|
+
"override" account (non-known-provider domain).
|
|
272
|
+
rmfmail -send <file> -account <id>
|
|
273
|
+
Same, but force the account.
|
|
274
|
+
|
|
275
|
+
rmfmail -register-mailto Register rmfmail as a Windows mailto: handler
|
|
276
|
+
rmfmail -unregister-mailto Remove the mailto: handler registration
|
|
263
277
|
```
|
|
264
278
|
|
|
279
|
+
### -send
|
|
280
|
+
|
|
281
|
+
Drop a raw `.ltr` or `.eml` file into the outbox without going through
|
|
282
|
+
compose. Two paths under the hood:
|
|
283
|
+
|
|
284
|
+
- `rmfmail -send <file>` copies into `~/.rmfmail/outbox/<basename>` (general
|
|
285
|
+
outbox). The running daemon's outbox sweep parses `From:` and routes the
|
|
286
|
+
file into `outbox/<accountId>/` based on:
|
|
287
|
+
1. exact match against an account's email,
|
|
288
|
+
2. known-provider domain match (gmail.com → first Gmail account; outlook.com /
|
|
289
|
+
hotmail.com / live.com → first Outlook account),
|
|
290
|
+
3. first account on a non-known-provider domain (the "override" account).
|
|
291
|
+
|
|
292
|
+
- `rmfmail -send <file> -account <id>` skips routing and copies directly
|
|
293
|
+
into `~/.rmfmail/outbox/<id>/`.
|
|
294
|
+
|
|
295
|
+
Bcc handling: the file's `Bcc:` header is preserved on disk. The SMTP path
|
|
296
|
+
(Gmail accounts) strips it from the wire bytes and adds the Bcc addresses
|
|
297
|
+
to the SMTP envelope; the IMAP-Outbox path (Dovecot/etc.) uploads the file
|
|
298
|
+
intact and lets the server-side outbox-drain sieve do the strip.
|
|
299
|
+
|
|
300
|
+
The CLI exits immediately. If the daemon isn't running, the file queues
|
|
301
|
+
until next launch. To send right now, also run `rmfmail` (or have a daemon
|
|
302
|
+
already running) — the outbox sweep ticks every 10 s.
|
|
303
|
+
|
|
304
|
+
### Mailto handler (Windows)
|
|
305
|
+
|
|
306
|
+
`rmfmail -register-mailto` writes the HKCU registry keys so rmfmail
|
|
307
|
+
appears in the Windows "Select an app to open this 'mailto' link" picker
|
|
308
|
+
(and in Settings → Apps → Default apps). The picker entry launches
|
|
309
|
+
`%LOCALAPPDATA%\rmfmail\bin\rmfmailto.exe` which shells out to the rmfmail
|
|
310
|
+
daemon with the parsed mailto URL.
|
|
311
|
+
|
|
312
|
+
To make rmfmail the *active default* for mailto (rather than just a
|
|
313
|
+
candidate), open Settings → Apps → Default apps, search for rmfmail, and
|
|
314
|
+
click "Set default" for the mailto link type. Windows 11 enforces a hash
|
|
315
|
+
on the UserChoice key so this final step can't be automated without
|
|
316
|
+
MSIX packaging or a hash-aware helper.
|
|
317
|
+
|
|
318
|
+
`rmfmail -unregister-mailto` removes the registration. Run this before
|
|
319
|
+
`-register-mailto` if the picker is showing a stale "Node.js JavaScript
|
|
320
|
+
Runtime" entry from an older install.
|
|
321
|
+
|
|
265
322
|
### -repair vs -rebuild
|
|
266
323
|
|
|
267
324
|
**-repair** clears message metadata (subjects, flags, sender names) from the database but preserves your downloaded `.eml` message files. Folder sync state resets so rmfmail re-fetches all envelopes on next run. Use this when subjects show garbled characters.
|
package/bin/mailx.js
CHANGED
|
@@ -2,21 +2,49 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* rmfmail -- email client
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* rmfmail
|
|
11
|
-
* rmfmail
|
|
12
|
-
* rmfmail -
|
|
13
|
-
* rmfmail -
|
|
14
|
-
* rmfmail -
|
|
15
|
-
* rmfmail -
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* rmfmail -
|
|
19
|
-
*
|
|
5
|
+
* Flag style: single-dash is canonical (-kill, -setup, ...). The parser also
|
|
6
|
+
* accepts double-dash (--kill, --setup) as a synonym for every flag — old
|
|
7
|
+
* scripts that used --server / --email / etc. keep working.
|
|
8
|
+
*
|
|
9
|
+
* Launch:
|
|
10
|
+
* rmfmail Start daemon + open WebView (IPC, no TCP)
|
|
11
|
+
* rmfmail -server Start Express HTTP server (dev/remote)
|
|
12
|
+
* rmfmail -no-browser Server mode without auto-opening a browser
|
|
13
|
+
* rmfmail -another Don't replace any existing rmfmail daemon
|
|
14
|
+
* rmfmail -verbose Echo logs to terminal (default: log file only)
|
|
15
|
+
* rmfmail -debug-server Launch debug introspection server
|
|
16
|
+
*
|
|
17
|
+
* Commands (exit immediately):
|
|
18
|
+
* rmfmail -kill Kill running rmfmail daemon + WebView
|
|
19
|
+
* rmfmail -v / -version Show version and exit
|
|
20
|
+
* rmfmail -setup Interactive first-time account setup (CLI)
|
|
21
|
+
* rmfmail -add Add another account (CLI)
|
|
22
|
+
* rmfmail -test Test IMAP/SMTP connectivity for all accounts
|
|
23
|
+
* rmfmail -rebuild Wipe local cache, re-sync everything from IMAP
|
|
24
|
+
* rmfmail -repair Re-sync metadata (fix corrupt subjects), keeps .eml files
|
|
25
|
+
* rmfmail -reauth Clear cached OAuth tokens; next start re-consents
|
|
26
|
+
* (use when new Google scopes have been added)
|
|
27
|
+
* rmfmail -log Print log file path and exit
|
|
28
|
+
* rmfmail -email <addr> First-time setup with this email (skips prompt)
|
|
29
|
+
* rmfmail -import <file> Import accounts.jsonc into GDrive and merge
|
|
30
|
+
* rmfmail -send <file> Enqueue a .ltr/.eml for sending — daemon auto-routes
|
|
31
|
+
* by parsing the file's `From:` header against
|
|
32
|
+
* configured accounts. Falls back to the first
|
|
33
|
+
* "override" account (non-known-provider domain).
|
|
34
|
+
* rmfmail -send <file> -account <id>
|
|
35
|
+
* Same, but force the account (skips auto-routing).
|
|
36
|
+
*
|
|
37
|
+
* Mailto handler (Windows):
|
|
38
|
+
* rmfmail -register-mailto Register as the OS-level mailto: handler so
|
|
39
|
+
* rmfmail appears in the "Open this 'mailto'
|
|
40
|
+
* link" picker (Settings → Default apps to set
|
|
41
|
+
* it as the active default).
|
|
42
|
+
* rmfmail -unregister-mailto Remove the mailto: handler registration.
|
|
43
|
+
* rmfmail -mailto <url> (internal) Decode a mailto URL and open compose.
|
|
44
|
+
*
|
|
45
|
+
* Internal:
|
|
46
|
+
* rmfmail -daemon (internal) marker for the detached daemon respawn.
|
|
47
|
+
* rmfmail -allow-elevated Bypass the admin/root refusal (debug only).
|
|
20
48
|
*/
|
|
21
49
|
import fs from "node:fs";
|
|
22
50
|
import path from "node:path";
|
|
@@ -109,6 +137,45 @@ const isDaemon = hasFlag("daemon"); // internal: re-spawned detached process
|
|
|
109
137
|
}
|
|
110
138
|
}
|
|
111
139
|
}
|
|
140
|
+
// -send <file> [-account <id>]: enqueue a .ltr/.eml from disk for sending.
|
|
141
|
+
// Just drops the file into `~/.rmfmail/outbox/` (or `~/.rmfmail/outbox/<id>/`
|
|
142
|
+
// when -account is given) and exits. The running daemon's outbox sweep picks
|
|
143
|
+
// it up within 10 s; if the daemon isn't running, the file queues until next
|
|
144
|
+
// launch. Routing (auto-account from `From:` header) is handled by
|
|
145
|
+
// ImapManager.routeGeneralOutbox() inside the daemon — keeps the CLI thin.
|
|
146
|
+
{
|
|
147
|
+
const sendIdx = args.findIndex(a => a === "-send" || a === "--send");
|
|
148
|
+
if (sendIdx !== -1) {
|
|
149
|
+
const file = args[sendIdx + 1];
|
|
150
|
+
if (!file) {
|
|
151
|
+
console.error("Usage: rmfmail -send <file> [-account <accountId>]");
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
if (!fs.existsSync(file)) {
|
|
155
|
+
console.error(`rmfmail -send: file not found: ${file}`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
const acctIdx = args.findIndex(a => a === "-account" || a === "--account");
|
|
159
|
+
const accountId = acctIdx !== -1 ? args[acctIdx + 1] : "";
|
|
160
|
+
const { getConfigDir } = await import("@bobfrankston/mailx-settings");
|
|
161
|
+
const outboxRoot = path.join(getConfigDir(), "outbox");
|
|
162
|
+
const targetDir = accountId ? path.join(outboxRoot, accountId) : outboxRoot;
|
|
163
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
164
|
+
const now = new Date();
|
|
165
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
166
|
+
const ts = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}_${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}-${String(Math.floor(Math.random() * 10000)).padStart(4, "0")}.ltr`;
|
|
167
|
+
const target = path.join(targetDir, ts);
|
|
168
|
+
fs.copyFileSync(file, target);
|
|
169
|
+
if (accountId) {
|
|
170
|
+
console.log(`Queued ${path.basename(file)} → outbox/${accountId}/${ts}`);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
console.log(`Queued ${path.basename(file)} → outbox/${ts} (daemon will auto-route by From: header)`);
|
|
174
|
+
}
|
|
175
|
+
console.log("Outbox sweep picks it up within 10 s (start rmfmail if it isn't running).");
|
|
176
|
+
process.exit(0);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
112
179
|
if (hasFlag("register-mailto") || hasFlag("unregister-mailto")) {
|
|
113
180
|
const unregister = hasFlag("unregister-mailto");
|
|
114
181
|
if (process.platform !== "win32") {
|
|
@@ -426,13 +493,41 @@ const rebuildMode = hasFlag("rebuild");
|
|
|
426
493
|
const repairMode = hasFlag("repair");
|
|
427
494
|
const importMode = hasFlag("import");
|
|
428
495
|
// Validate arguments
|
|
429
|
-
const knownFlags = ["verbose", "kill", "v", "version", "setup", "add", "test", "rebuild", "repair", "log", "import", "email", "mail", "daemon", "reauth", "mailto", "register-mailto", "unregister-mailto", "allow-elevated", "another", "server", "debug-server"];
|
|
496
|
+
const knownFlags = ["verbose", "kill", "v", "version", "setup", "add", "test", "rebuild", "repair", "log", "import", "email", "mail", "daemon", "reauth", "mailto", "register-mailto", "unregister-mailto", "allow-elevated", "another", "server", "no-browser", "debug-server", "send", "account"];
|
|
430
497
|
for (const arg of args) {
|
|
431
498
|
// Strip a leading -/-- and any `=value` suffix before checking.
|
|
432
499
|
const flag = arg.replace(/^--?/, "").split("=")[0];
|
|
433
500
|
if (arg.startsWith("-") && !knownFlags.includes(flag)) {
|
|
434
501
|
console.error(`Unknown option: ${arg}`);
|
|
435
|
-
console.error("Usage: rmfmail [
|
|
502
|
+
console.error("Usage: rmfmail [options] (-- prefix also accepted for every flag)\n" +
|
|
503
|
+
" Launch:\n" +
|
|
504
|
+
" (no args) Start daemon + open WebView (IPC, no TCP)\n" +
|
|
505
|
+
" -server Start Express HTTP server (dev/remote)\n" +
|
|
506
|
+
" -no-browser Server mode without auto-opening a browser\n" +
|
|
507
|
+
" -another Don't replace any existing rmfmail daemon\n" +
|
|
508
|
+
" -verbose Echo logs to terminal (default: log file only)\n" +
|
|
509
|
+
" -debug-server Launch debug introspection server\n" +
|
|
510
|
+
" Commands (exit immediately):\n" +
|
|
511
|
+
" -kill Kill running rmfmail daemon + WebView\n" +
|
|
512
|
+
" -v / -version Print version and exit\n" +
|
|
513
|
+
" -setup Interactive first-time account setup (CLI)\n" +
|
|
514
|
+
" -add Add another account (CLI)\n" +
|
|
515
|
+
" -test Test IMAP/SMTP connectivity for all accounts\n" +
|
|
516
|
+
" -rebuild Wipe local cache, re-sync everything\n" +
|
|
517
|
+
" -repair Re-sync metadata (keeps .eml files)\n" +
|
|
518
|
+
" -reauth Clear cached OAuth tokens; re-consent on next start\n" +
|
|
519
|
+
" -log Print log file path and exit\n" +
|
|
520
|
+
" -email <addr> First-time setup with this email (skips prompt)\n" +
|
|
521
|
+
" -import <file> Import accounts.jsonc into GDrive and merge\n" +
|
|
522
|
+
" -send <file> Enqueue a .ltr/.eml for sending (auto-route by From:)\n" +
|
|
523
|
+
" -send <file> -account <id> Enqueue under a specific account\n" +
|
|
524
|
+
" Mailto handler (Windows):\n" +
|
|
525
|
+
" -register-mailto Register as the OS-level mailto: handler\n" +
|
|
526
|
+
" -unregister-mailto Remove the mailto: handler registration\n" +
|
|
527
|
+
" -mailto <url> (internal) Decode a mailto URL and open compose\n" +
|
|
528
|
+
" Internal:\n" +
|
|
529
|
+
" -daemon (internal) marker for the detached daemon respawn\n" +
|
|
530
|
+
" -allow-elevated Bypass the admin/root refusal (debug only)");
|
|
436
531
|
process.exit(1);
|
|
437
532
|
}
|
|
438
533
|
}
|