@bobfrankston/mailx 1.0.182 → 1.0.183
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.183",
|
|
4
4
|
"description": "Local-first email client with IMAP sync and standalone native app",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/mailx.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@bobfrankston/iflow-node": "^0.1.2",
|
|
25
25
|
"@bobfrankston/miscinfo": "^1.0.8",
|
|
26
26
|
"@bobfrankston/oauthsupport": "^1.0.21",
|
|
27
|
-
"@bobfrankston/msger": "^0.1.
|
|
27
|
+
"@bobfrankston/msger": "^0.1.233",
|
|
28
28
|
"@capacitor/android": "^8.3.0",
|
|
29
29
|
"@capacitor/cli": "^8.3.0",
|
|
30
30
|
"@capacitor/core": "^8.3.0",
|
|
@@ -178,7 +178,7 @@ export declare class ImapManager extends EventEmitter {
|
|
|
178
178
|
private readonly hostname;
|
|
179
179
|
/** Ensure Outbox folder exists, create if needed */
|
|
180
180
|
private ensureOutbox;
|
|
181
|
-
/** Save a
|
|
181
|
+
/** Save a copy of outgoing mail — label is a subdirectory (editing/queued/sent) */
|
|
182
182
|
private saveSendingCopy;
|
|
183
183
|
/** Queue a message for sending. Tries IMAP Outbox, falls back to local file. */
|
|
184
184
|
queueOutgoing(accountId: string, rawMessage: string | Buffer): Promise<void>;
|
|
@@ -1629,20 +1629,19 @@ export class ImapManager extends EventEmitter {
|
|
|
1629
1629
|
outbox = this.findFolder(accountId, "outbox");
|
|
1630
1630
|
return outbox?.path || "Outbox";
|
|
1631
1631
|
}
|
|
1632
|
-
/** Save a
|
|
1632
|
+
/** Save a copy of outgoing mail — label is a subdirectory (editing/queued/sent) */
|
|
1633
1633
|
saveSendingCopy(accountId, rawMessage, label) {
|
|
1634
1634
|
try {
|
|
1635
|
-
const
|
|
1636
|
-
fs.mkdirSync(
|
|
1635
|
+
const dir = path.join(getConfigDir(), "sending", accountId, label);
|
|
1636
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1637
1637
|
const now = new Date();
|
|
1638
1638
|
const pad2 = (n) => String(n).padStart(2, "0");
|
|
1639
1639
|
const ts = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}_${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
console.log(` [sending] Saved debug copy: ${filename}`);
|
|
1640
|
+
fs.writeFileSync(path.join(dir, `${ts}.eml`), rawMessage);
|
|
1641
|
+
console.log(` [sending] ${label}/${ts}.eml`);
|
|
1643
1642
|
}
|
|
1644
1643
|
catch (e) {
|
|
1645
|
-
console.error(` [sending] Failed to save
|
|
1644
|
+
console.error(` [sending] Failed to save copy: ${e.message}`);
|
|
1646
1645
|
}
|
|
1647
1646
|
}
|
|
1648
1647
|
/** Queue a message for sending. Tries IMAP Outbox, falls back to local file. */
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* Both the Express API (mailx-api) and the Android bridge call these functions.
|
|
5
5
|
*/
|
|
6
6
|
import * as dns from "node:dns/promises";
|
|
7
|
-
import
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { loadSettings, saveSettings, loadAccounts, loadAccountsAsync, saveAccounts, initCloudConfig, loadAllowlist, saveAllowlist, loadAutocomplete, saveAutocomplete, getStorePath, getStorageInfo, getConfigDir } from "@bobfrankston/mailx-settings";
|
|
8
10
|
import { simpleParser } from "mailparser";
|
|
9
11
|
// ── Quoted-printable encoding (readable in debug .eml files) ──
|
|
10
12
|
function encodeQuotedPrintable(text) {
|
|
@@ -538,6 +540,21 @@ export class MailxService {
|
|
|
538
540
|
`MIME-Version: 1.0`, `Content-Type: text/html; charset=UTF-8`, `Content-Transfer-Encoding: quoted-printable`,
|
|
539
541
|
].filter(h => h !== null).join("\r\n");
|
|
540
542
|
const raw = `${headers}\r\n\r\n${bodyEncoded}`;
|
|
543
|
+
// Save local editing copy — crash recovery, keep last 3
|
|
544
|
+
try {
|
|
545
|
+
const editingDir = path.join(getConfigDir(), "sending", accountId, "editing");
|
|
546
|
+
fs.mkdirSync(editingDir, { recursive: true });
|
|
547
|
+
const pad2 = (n) => String(n).padStart(2, "0");
|
|
548
|
+
const now = new Date();
|
|
549
|
+
const ts = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}_${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
|
|
550
|
+
fs.writeFileSync(path.join(editingDir, `${ts}.eml`), raw);
|
|
551
|
+
// Keep only last 3
|
|
552
|
+
const files = fs.readdirSync(editingDir).filter(f => f.endsWith(".eml")).sort();
|
|
553
|
+
while (files.length > 3) {
|
|
554
|
+
fs.unlinkSync(path.join(editingDir, files.shift()));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
catch { /* ignore */ }
|
|
541
558
|
const uid = await this.imapManager.saveDraft(accountId, raw, previousDraftUid, id);
|
|
542
559
|
return { uid, draftId: id };
|
|
543
560
|
}
|