@zaclinley/dsh-mailharbor 0.1.0 → 0.2.1
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/CHANGELOG.md +24 -5
- package/README.md +29 -3
- package/README.zh.md +27 -3
- package/lib/client.js +467 -334
- package/lib/client.js.map +4 -4
- package/lib/index.js +44 -34
- package/lib/index.js.map +3 -3
- package/package.json +4 -2
- package/scripts/migrate-legacy.mjs +318 -0
package/lib/index.js
CHANGED
|
@@ -74,7 +74,7 @@ __export(smtp_exports, {
|
|
|
74
74
|
verifySmtp: () => verifySmtp
|
|
75
75
|
});
|
|
76
76
|
import nodemailer from "nodemailer";
|
|
77
|
-
function transportOptions(settings, credentials) {
|
|
77
|
+
function transportOptions(settings, credentials, security = {}) {
|
|
78
78
|
const secure = settings.secure !== false;
|
|
79
79
|
return {
|
|
80
80
|
host: settings.host,
|
|
@@ -83,21 +83,21 @@ function transportOptions(settings, credentials) {
|
|
|
83
83
|
// Plain submission ports must upgrade; never send credentials in the clear.
|
|
84
84
|
requireTLS: !secure,
|
|
85
85
|
auth: credentials.accessToken !== void 0 ? { type: "OAuth2", user: credentials.user, accessToken: credentials.accessToken } : { user: credentials.user, pass: credentials.pass ?? "" },
|
|
86
|
-
tls: { rejectUnauthorized: true, servername: settings.host },
|
|
86
|
+
tls: { rejectUnauthorized: security.allowSelfSigned !== true, servername: settings.host },
|
|
87
87
|
connectionTimeout: 2e4,
|
|
88
88
|
greetingTimeout: 2e4,
|
|
89
89
|
socketTimeout: 12e4,
|
|
90
90
|
pool: false
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
function createTransport(settings, credentials) {
|
|
94
|
-
return nodemailer.createTransport(transportOptions(settings, credentials));
|
|
93
|
+
function createTransport(settings, credentials, security = {}) {
|
|
94
|
+
return nodemailer.createTransport(transportOptions(settings, credentials, security));
|
|
95
95
|
}
|
|
96
96
|
function recipientsOf(value) {
|
|
97
97
|
return value.split(/[,;]/).map((part) => addressOf(part)).filter((address) => isEmail(address));
|
|
98
98
|
}
|
|
99
|
-
async function verifySmtp(settings, credentials) {
|
|
100
|
-
const transport = createTransport(settings, credentials);
|
|
99
|
+
async function verifySmtp(settings, credentials, security = {}) {
|
|
100
|
+
const transport = createTransport(settings, credentials, security);
|
|
101
101
|
try {
|
|
102
102
|
await transport.verify();
|
|
103
103
|
return { ok: true, host: settings.host, port: Number(settings.port) };
|
|
@@ -105,13 +105,13 @@ async function verifySmtp(settings, credentials) {
|
|
|
105
105
|
transport.close();
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
async function sendMail(settings, credentials, account, mail) {
|
|
108
|
+
async function sendMail(settings, credentials, account, mail, security = {}) {
|
|
109
109
|
const from = addressOf(mail.from ?? account);
|
|
110
110
|
if (!isEmail(from)) throw new Error("\u53D1\u4EF6\u4EBA\u5730\u5740\u65E0\u6548");
|
|
111
111
|
const to = recipientsOf(mail.to);
|
|
112
112
|
const cc = recipientsOf(mail.cc ?? "");
|
|
113
113
|
if (to.length === 0) throw new Error("\u6536\u4EF6\u4EBA\u4E0D\u80FD\u4E3A\u7A7A");
|
|
114
|
-
const transport = createTransport(settings, credentials);
|
|
114
|
+
const transport = createTransport(settings, credentials, security);
|
|
115
115
|
try {
|
|
116
116
|
const info = await transport.sendMail({
|
|
117
117
|
from: settings.fromName === "" ? from : { name: settings.fromName, address: from },
|
|
@@ -1452,6 +1452,16 @@ var Router = class {
|
|
|
1452
1452
|
|
|
1453
1453
|
// src/host/api.ts
|
|
1454
1454
|
init_smtp();
|
|
1455
|
+
|
|
1456
|
+
// src/host/html.ts
|
|
1457
|
+
function htmlToText(html) {
|
|
1458
|
+
return html.replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|tr|h[1-6])>/gi, "\n").replace(/<li[^>]*>/gi, "\u2022 ").replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\n{3,}/g, "\n\n").trim();
|
|
1459
|
+
}
|
|
1460
|
+
function escapeHtml(value) {
|
|
1461
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
// src/host/api.ts
|
|
1455
1465
|
var API_PREFIX = "/mail-plugin/api";
|
|
1456
1466
|
function createApiHandler(runtime) {
|
|
1457
1467
|
const router = buildRouter(runtime);
|
|
@@ -1964,12 +1974,6 @@ ${signature}`;
|
|
|
1964
1974
|
);
|
|
1965
1975
|
return { ok: true, result };
|
|
1966
1976
|
}
|
|
1967
|
-
function htmlToText(html) {
|
|
1968
|
-
return html.replace(/<style[\s\S]*?<\/style>/gi, "").replace(/<script[\s\S]*?<\/script>/gi, "").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|tr|h[1-6])>/gi, "\n").replace(/<li[^>]*>/gi, "\u2022 ").replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/\n{3,}/g, "\n\n").trim();
|
|
1969
|
-
}
|
|
1970
|
-
function escapeHtml(value) {
|
|
1971
|
-
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
1972
|
-
}
|
|
1973
1977
|
|
|
1974
1978
|
// src/host/runtime.ts
|
|
1975
1979
|
import { statSync } from "node:fs";
|
|
@@ -2360,13 +2364,13 @@ var MailHarborRuntime = class {
|
|
|
2360
2364
|
const live = new Set(this.config.accounts.map((account) => account.id));
|
|
2361
2365
|
for (const id of [...this.providers.keys()]) {
|
|
2362
2366
|
if (!live.has(id)) {
|
|
2363
|
-
void this.providers.get(id)?.dispose();
|
|
2367
|
+
void this.providers.get(id)?.value.dispose();
|
|
2364
2368
|
this.providers.delete(id);
|
|
2365
2369
|
}
|
|
2366
2370
|
}
|
|
2367
2371
|
for (const id of [...this.databases.keys()]) {
|
|
2368
2372
|
if (!live.has(id)) {
|
|
2369
|
-
this.databases.get(id)?.close();
|
|
2373
|
+
this.databases.get(id)?.value.close();
|
|
2370
2374
|
this.databases.delete(id);
|
|
2371
2375
|
}
|
|
2372
2376
|
}
|
|
@@ -2375,9 +2379,9 @@ var MailHarborRuntime = class {
|
|
|
2375
2379
|
}
|
|
2376
2380
|
/** Drop cached connections and stores for one account after a settings change. */
|
|
2377
2381
|
invalidate(accountId) {
|
|
2378
|
-
void this.providers.get(accountId)?.dispose();
|
|
2382
|
+
void this.providers.get(accountId)?.value.dispose();
|
|
2379
2383
|
this.providers.delete(accountId);
|
|
2380
|
-
this.databases.get(accountId)?.close();
|
|
2384
|
+
this.databases.get(accountId)?.value.close();
|
|
2381
2385
|
this.databases.delete(accountId);
|
|
2382
2386
|
this.draftStores.delete(accountId);
|
|
2383
2387
|
this.readStores.delete(accountId);
|
|
@@ -2408,37 +2412,43 @@ var MailHarborRuntime = class {
|
|
|
2408
2412
|
return account.imap;
|
|
2409
2413
|
}
|
|
2410
2414
|
provider(account) {
|
|
2415
|
+
const signature = `${account.imap.host}:${String(account.imap.port)}:${String(account.imap.secure)}:${account.username}:${account.auth.type}`;
|
|
2411
2416
|
const existing = this.providers.get(account.id);
|
|
2412
|
-
if (existing !== void 0) return existing;
|
|
2417
|
+
if (existing !== void 0 && existing.signature === signature) return existing.value;
|
|
2418
|
+
if (existing !== void 0) void existing.value.dispose();
|
|
2413
2419
|
const created = new ImapProvider(account.imap, this.credentialsFor(account), {
|
|
2414
2420
|
onReconnect: () => {
|
|
2415
2421
|
}
|
|
2416
2422
|
});
|
|
2417
|
-
this.providers.set(account.id, created);
|
|
2423
|
+
this.providers.set(account.id, { signature, value: created });
|
|
2418
2424
|
return created;
|
|
2419
2425
|
}
|
|
2420
2426
|
database(account) {
|
|
2427
|
+
const root = this.paths(account);
|
|
2421
2428
|
const existing = this.databases.get(account.id);
|
|
2422
|
-
if (existing !== void 0) return existing;
|
|
2423
|
-
|
|
2429
|
+
if (existing !== void 0 && existing.signature === root.mailDb) return existing.value;
|
|
2430
|
+
if (existing !== void 0) existing.value.close();
|
|
2431
|
+
const created = new MailDatabase(root.mailDb, {
|
|
2424
2432
|
maxBodyChars: 4e5,
|
|
2425
|
-
attachmentsRoot:
|
|
2433
|
+
attachmentsRoot: root.attachments
|
|
2426
2434
|
});
|
|
2427
|
-
this.databases.set(account.id, created);
|
|
2435
|
+
this.databases.set(account.id, { signature: root.mailDb, value: created });
|
|
2428
2436
|
return created;
|
|
2429
2437
|
}
|
|
2430
2438
|
drafts(account) {
|
|
2439
|
+
const file = draftPath(this.paths(account).root);
|
|
2431
2440
|
const existing = this.draftStores.get(account.id);
|
|
2432
|
-
if (existing !== void 0) return existing;
|
|
2433
|
-
const created = new DraftStore(
|
|
2434
|
-
this.draftStores.set(account.id, created);
|
|
2441
|
+
if (existing !== void 0 && existing.signature === file) return existing.value;
|
|
2442
|
+
const created = new DraftStore(file, account.id);
|
|
2443
|
+
this.draftStores.set(account.id, { signature: file, value: created });
|
|
2435
2444
|
return created;
|
|
2436
2445
|
}
|
|
2437
2446
|
readState(account) {
|
|
2447
|
+
const file = join4(this.paths(account).root, "read-state.json");
|
|
2438
2448
|
const existing = this.readStores.get(account.id);
|
|
2439
|
-
if (existing !== void 0) return existing;
|
|
2440
|
-
const created = new ReadStateStore(
|
|
2441
|
-
this.readStores.set(account.id, created);
|
|
2449
|
+
if (existing !== void 0 && existing.signature === file) return existing.value;
|
|
2450
|
+
const created = new ReadStateStore(file);
|
|
2451
|
+
this.readStores.set(account.id, { signature: file, value: created });
|
|
2442
2452
|
return created;
|
|
2443
2453
|
}
|
|
2444
2454
|
backupStatus(account) {
|
|
@@ -2493,7 +2503,7 @@ var MailHarborRuntime = class {
|
|
|
2493
2503
|
status.running = false;
|
|
2494
2504
|
status.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2495
2505
|
if (status.exitCode === 0) status.lastSuccessAt = status.finishedAt;
|
|
2496
|
-
this.databases.get(account.id)?.close();
|
|
2506
|
+
this.databases.get(account.id)?.value.close();
|
|
2497
2507
|
this.databases.delete(account.id);
|
|
2498
2508
|
}
|
|
2499
2509
|
})();
|
|
@@ -2509,9 +2519,9 @@ var MailHarborRuntime = class {
|
|
|
2509
2519
|
async dispose() {
|
|
2510
2520
|
this.disposed = true;
|
|
2511
2521
|
for (const job of this.backups.values()) job.controller.abort();
|
|
2512
|
-
for (const provider of this.providers.values()) await provider.dispose();
|
|
2522
|
+
for (const provider of this.providers.values()) await provider.value.dispose();
|
|
2513
2523
|
this.providers.clear();
|
|
2514
|
-
for (const db of this.databases.values()) db.close();
|
|
2524
|
+
for (const db of this.databases.values()) db.value.close();
|
|
2515
2525
|
this.databases.clear();
|
|
2516
2526
|
}
|
|
2517
2527
|
};
|
|
@@ -2894,7 +2904,7 @@ ${page.items.map(
|
|
|
2894
2904
|
// src/host/index.ts
|
|
2895
2905
|
var name = "mailharbor";
|
|
2896
2906
|
var inject = ["webServer", "tools"];
|
|
2897
|
-
var VERSION2 = "0.1
|
|
2907
|
+
var VERSION2 = "0.2.1";
|
|
2898
2908
|
var ROUTE = "/mail-plugin";
|
|
2899
2909
|
function apply(ctx) {
|
|
2900
2910
|
const runtime = new MailHarborRuntime();
|