@bobfrankston/rmfmail 1.2.232 → 1.2.233
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/client/android-bootstrap.bundle.js +164 -152
- package/client/android-bootstrap.bundle.js.map +4 -4
- package/client/app.bundle.js +10 -104
- package/client/app.bundle.js.map +4 -4
- package/client/components/message-list.js +0 -60
- package/client/components/message-list.js.map +1 -1
- package/client/components/message-list.ts +0 -56
- package/client/compose/compose.bundle.js +1 -12
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/compose/compose.html +0 -8
- package/client/compose/ghost-text.js +0 -8
- package/client/compose/ghost-text.js.map +1 -1
- package/client/compose/ghost-text.ts +0 -6
- package/client/compose/spellcheck-core.js +0 -1
- package/client/compose/spellcheck-core.js.map +1 -1
- package/client/compose/spellcheck-core.ts +0 -1
- package/client/index.html +0 -8
- package/client/lib/local-service.js +0 -73
- package/client/lib/local-service.js.map +1 -1
- package/client/lib/local-service.ts +0 -71
- package/client/lib/local-store.js +0 -3
- package/client/lib/local-store.js.map +1 -1
- package/client/lib/local-store.ts +0 -4
- package/package.json +1 -3
- package/packages/mailx-host/index.d.ts +0 -1
- package/packages/mailx-host/index.d.ts.map +1 -1
- package/packages/mailx-host/index.js +0 -1
- package/packages/mailx-host/index.js.map +1 -1
- package/packages/mailx-host/index.ts +0 -1
- package/packages/mailx-host/package.json +1 -1
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +36 -139
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +36 -148
- package/packages/mailx-settings/cloud.d.ts +0 -5
- package/packages/mailx-settings/cloud.d.ts.map +1 -1
- package/packages/mailx-settings/cloud.js +0 -16
- package/packages/mailx-settings/cloud.js.map +1 -1
- package/packages/mailx-settings/cloud.ts +0 -12
- package/packages/mailx-settings/index.d.ts +0 -3
- package/packages/mailx-settings/index.d.ts.map +1 -1
- package/packages/mailx-settings/index.js +0 -5
- package/packages/mailx-settings/index.js.map +1 -1
- package/packages/mailx-settings/index.ts +0 -7
- package/packages/mailx-store-web/main-thread-host.d.ts +1 -1
- package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -1
- package/packages/mailx-store-web/main-thread-host.js +1 -38
- package/packages/mailx-store-web/main-thread-host.js.map +1 -1
- package/packages/mailx-store-web/main-thread-host.ts +0 -42
- package/packages/mailx-store-web/package.json +1 -1
- package/packages/mailx-store-web/web-service.d.ts.map +1 -1
- package/packages/mailx-store-web/web-service.js +28 -114
- package/packages/mailx-store-web/web-service.js.map +1 -1
- package/packages/mailx-store-web/web-service.ts +28 -124
- package/packages/mailx-store-web/web-settings.d.ts +0 -4
- package/packages/mailx-store-web/web-settings.d.ts.map +1 -1
- package/packages/mailx-store-web/web-settings.js +0 -29
- package/packages/mailx-store-web/web-settings.js.map +1 -1
- package/packages/mailx-store-web/web-settings.ts +0 -24
- package/packages/mailx-types/index.d.ts +2 -0
- package/packages/mailx-types/index.d.ts.map +1 -1
- package/packages/mailx-types/index.js +1 -0
- package/packages/mailx-types/index.js.map +1 -1
- package/packages/mailx-types/index.ts +2 -0
- package/packages/mailx-types/mime-build.d.ts +74 -0
- package/packages/mailx-types/mime-build.d.ts.map +1 -0
- package/packages/mailx-types/mime-build.js +160 -0
- package/packages/mailx-types/mime-build.js.map +1 -0
- package/packages/mailx-types/mime-build.ts +217 -0
- package/packages/mailx-types/package.json +1 -1
- package/packages/mailx-types/test/mime-build.test.mjs +200 -0
- package/client/components/calendar.js +0 -220
- package/client/components/calendar.js.map +0 -1
- package/client/components/calendar.ts +0 -213
- package/client/components/tasks.js +0 -261
- package/client/components/tasks.js.map +0 -1
- package/client/components/tasks.ts +0 -234
- package/packages/mailx-compose/.gitattributes +0 -10
- package/packages/mailx-compose/index.d.ts +0 -21
- package/packages/mailx-compose/index.d.ts.map +0 -1
- package/packages/mailx-compose/index.js +0 -66
- package/packages/mailx-compose/index.js.map +0 -1
- package/packages/mailx-compose/index.ts +0 -91
- package/packages/mailx-compose/package.json +0 -18
- package/packages/mailx-compose/tsconfig.json +0 -9
- package/packages/mailx-core/index.d.ts +0 -142
- package/packages/mailx-core/index.d.ts.map +0 -1
- package/packages/mailx-core/index.js +0 -430
- package/packages/mailx-core/index.js.map +0 -1
- package/packages/mailx-core/index.ts +0 -450
- package/packages/mailx-core/ipc.d.ts +0 -13
- package/packages/mailx-core/ipc.d.ts.map +0 -1
- package/packages/mailx-core/ipc.js +0 -56
- package/packages/mailx-core/ipc.js.map +0 -1
- package/packages/mailx-core/ipc.ts +0 -62
- package/packages/mailx-core/package.json +0 -18
- package/packages/mailx-core/tsconfig.json +0 -9
- package/packages/mailx-send/.gitattributes +0 -10
- package/packages/mailx-send/README.md +0 -217
- package/packages/mailx-send/cli-queue.d.ts +0 -11
- package/packages/mailx-send/cli-queue.d.ts.map +0 -1
- package/packages/mailx-send/cli-queue.js +0 -59
- package/packages/mailx-send/cli-queue.js.map +0 -1
- package/packages/mailx-send/cli-queue.ts +0 -62
- package/packages/mailx-send/cli-send.d.ts +0 -17
- package/packages/mailx-send/cli-send.d.ts.map +0 -1
- package/packages/mailx-send/cli-send.js +0 -75
- package/packages/mailx-send/cli-send.js.map +0 -1
- package/packages/mailx-send/cli-send.ts +0 -83
- package/packages/mailx-send/cli.d.ts +0 -22
- package/packages/mailx-send/cli.d.ts.map +0 -1
- package/packages/mailx-send/cli.js +0 -115
- package/packages/mailx-send/cli.js.map +0 -1
- package/packages/mailx-send/cli.ts +0 -126
- package/packages/mailx-send/index.d.ts +0 -77
- package/packages/mailx-send/index.d.ts.map +0 -1
- package/packages/mailx-send/index.js +0 -269
- package/packages/mailx-send/index.js.map +0 -1
- package/packages/mailx-send/index.ts +0 -338
- package/packages/mailx-send/mailsend/README.md +0 -133
- package/packages/mailx-send/mailsend/cli.d.ts +0 -12
- package/packages/mailx-send/mailsend/cli.d.ts.map +0 -1
- package/packages/mailx-send/mailsend/cli.js +0 -70
- package/packages/mailx-send/mailsend/cli.js.map +0 -1
- package/packages/mailx-send/mailsend/cli.ts +0 -81
- package/packages/mailx-send/mailsend/index.d.ts +0 -77
- package/packages/mailx-send/mailsend/index.d.ts.map +0 -1
- package/packages/mailx-send/mailsend/index.js +0 -264
- package/packages/mailx-send/mailsend/index.js.map +0 -1
- package/packages/mailx-send/mailsend/index.ts +0 -336
- package/packages/mailx-send/mailsend/package-lock.json +0 -65
- package/packages/mailx-send/mailsend/package.json +0 -26
- package/packages/mailx-send/mailsend/tsconfig.json +0 -21
- package/packages/mailx-send/package-lock.json +0 -65
- package/packages/mailx-send/package.json +0 -37
- package/packages/mailx-send/tsconfig.json +0 -21
- package/packages/mailx-server/.gitattributes +0 -10
- package/packages/mailx-server/index.d.ts +0 -8
- package/packages/mailx-server/index.d.ts.map +0 -1
- package/packages/mailx-server/index.js +0 -412
- package/packages/mailx-server/index.js.map +0 -1
- package/packages/mailx-server/index.ts +0 -445
- package/packages/mailx-server/package.json +0 -28
- package/packages/mailx-server/tsconfig.json +0 -9
- package/packages/mailx-server/tsconfig.tsbuildinfo +0 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-40260 → node_modules.npmglobalize-stash-40004}/.package-lock.json +0 -0
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* mailx-send CLI — queue and send email.
|
|
4
|
-
*
|
|
5
|
-
* Queue management (process queued .ltr files):
|
|
6
|
-
* mailx-send --process Process all account queues now
|
|
7
|
-
* mailx-send --process -q gmail Process only the gmail queue
|
|
8
|
-
* mailx-send --status Show queue status
|
|
9
|
-
*
|
|
10
|
-
* Create and queue a new message:
|
|
11
|
-
* mailx-send --new --to addr --subject "text" --body "text"
|
|
12
|
-
* mailx-send --new -q gmail --from "Bob <bob@gmail.com>" --to addr --subject "text"
|
|
13
|
-
* mailx-send --new --json message.json Read message from JSON file
|
|
14
|
-
* echo '{"to":["a@b.com"],...}' | mailx-send --new --json - Read from stdin
|
|
15
|
-
*
|
|
16
|
-
* JSON message format:
|
|
17
|
-
* { "to": ["addr"], "cc": ["addr"], "from": "Name <addr>",
|
|
18
|
-
* "subject": "text", "text": "body", "html": "<p>body</p>",
|
|
19
|
-
* "accountId": "iecc" }
|
|
20
|
-
*/
|
|
21
|
-
import * as fs from "node:fs";
|
|
22
|
-
import { initMailSend, queueMessage } from "./index.js";
|
|
23
|
-
const args = process.argv.slice(2);
|
|
24
|
-
function getArg(name) {
|
|
25
|
-
const shorts = { q: "queue" };
|
|
26
|
-
const longIdx = args.indexOf(`--${name}`);
|
|
27
|
-
const shortKey = Object.entries(shorts).find(([, v]) => v === name)?.[0];
|
|
28
|
-
const shortIdx = shortKey ? args.indexOf(`-${shortKey}`) : -1;
|
|
29
|
-
const i = Math.max(longIdx, shortIdx);
|
|
30
|
-
if (i === -1 || i + 1 >= args.length)
|
|
31
|
-
return undefined;
|
|
32
|
-
return args[i + 1];
|
|
33
|
-
}
|
|
34
|
-
function hasFlag(name) {
|
|
35
|
-
return args.includes(`--${name}`);
|
|
36
|
-
}
|
|
37
|
-
// Load config
|
|
38
|
-
const configPath = getArg("config") || "mailsend.json";
|
|
39
|
-
if (!fs.existsSync(configPath)) {
|
|
40
|
-
console.error(`Config file not found: ${configPath}`);
|
|
41
|
-
console.error(`Create a mailsend.json with baseDir, accounts, etc.`);
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
45
|
-
const sender = initMailSend(config);
|
|
46
|
-
const accountId = getArg("queue") || config.defaultAccount || "";
|
|
47
|
-
// ── Queue management ──
|
|
48
|
-
if (hasFlag("status")) {
|
|
49
|
-
const status = sender.getStatus();
|
|
50
|
-
for (const [id, s] of Object.entries(status)) {
|
|
51
|
-
console.log(` ${id}: ${s.pending} pending, ${s.failed} failed`);
|
|
52
|
-
}
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
if (hasFlag("process") && !hasFlag("new")) {
|
|
56
|
-
if (accountId && accountId !== config.defaultAccount) {
|
|
57
|
-
await sender.processQueue(accountId);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
await sender.processAllQueues();
|
|
61
|
-
}
|
|
62
|
-
process.exit(0);
|
|
63
|
-
}
|
|
64
|
-
// ── Create new message ──
|
|
65
|
-
if (hasFlag("new")) {
|
|
66
|
-
let msg = {};
|
|
67
|
-
const jsonArg = getArg("json");
|
|
68
|
-
if (jsonArg) {
|
|
69
|
-
// Load from JSON file or stdin
|
|
70
|
-
const raw = jsonArg === "-"
|
|
71
|
-
? fs.readFileSync(0, "utf-8") // stdin
|
|
72
|
-
: fs.readFileSync(jsonArg, "utf-8");
|
|
73
|
-
msg = JSON.parse(raw);
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
// Build from CLI args
|
|
77
|
-
const to = getArg("to");
|
|
78
|
-
if (!to) {
|
|
79
|
-
console.error("--new requires --to or --json");
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
msg = {
|
|
83
|
-
to: to.split(",").map(s => s.trim()),
|
|
84
|
-
subject: getArg("subject") || "(no subject)",
|
|
85
|
-
text: getArg("body") || "",
|
|
86
|
-
html: getArg("html"),
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
// Set from/account
|
|
90
|
-
const acctId = msg.accountId || accountId;
|
|
91
|
-
const acct = config.accounts[acctId];
|
|
92
|
-
if (!acct) {
|
|
93
|
-
console.error(`Unknown account: ${acctId}`);
|
|
94
|
-
console.error(`Available: ${Object.keys(config.accounts).join(", ")}`);
|
|
95
|
-
process.exit(1);
|
|
96
|
-
}
|
|
97
|
-
msg.from = msg.from || getArg("from") || acct.from || acct.user;
|
|
98
|
-
msg.accountId = acctId;
|
|
99
|
-
if (!msg.to?.length) {
|
|
100
|
-
console.error("Message must have at least one recipient (to)");
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
const filename = queueMessage(msg);
|
|
104
|
-
console.log(`Queued: ${filename}`);
|
|
105
|
-
setTimeout(() => process.exit(0), 2000);
|
|
106
|
-
}
|
|
107
|
-
else if (!hasFlag("status") && !hasFlag("process")) {
|
|
108
|
-
console.error("Usage:");
|
|
109
|
-
console.error(" mailx-send --new --to addr --subject text [--body text] [-q account]");
|
|
110
|
-
console.error(" mailx-send --new --json message.json [-q account]");
|
|
111
|
-
console.error(" mailx-send --process [-q account]");
|
|
112
|
-
console.error(" mailx-send --status");
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=cli.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* mailx-send CLI — queue and send email.
|
|
4
|
-
*
|
|
5
|
-
* Queue management (process queued .ltr files):
|
|
6
|
-
* mailx-send --process Process all account queues now
|
|
7
|
-
* mailx-send --process -q gmail Process only the gmail queue
|
|
8
|
-
* mailx-send --status Show queue status
|
|
9
|
-
*
|
|
10
|
-
* Create and queue a new message:
|
|
11
|
-
* mailx-send --new --to addr --subject "text" --body "text"
|
|
12
|
-
* mailx-send --new -q gmail --from "Bob <bob@gmail.com>" --to addr --subject "text"
|
|
13
|
-
* mailx-send --new --json message.json Read message from JSON file
|
|
14
|
-
* echo '{"to":["a@b.com"],...}' | mailx-send --new --json - Read from stdin
|
|
15
|
-
*
|
|
16
|
-
* JSON message format:
|
|
17
|
-
* { "to": ["addr"], "cc": ["addr"], "from": "Name <addr>",
|
|
18
|
-
* "subject": "text", "text": "body", "html": "<p>body</p>",
|
|
19
|
-
* "accountId": "iecc" }
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import * as fs from "node:fs";
|
|
23
|
-
import { initMailSend, queueMessage, type MailSendConfig, type MailMessage } from "./index.js";
|
|
24
|
-
|
|
25
|
-
const args = process.argv.slice(2);
|
|
26
|
-
|
|
27
|
-
function getArg(name: string): string | undefined {
|
|
28
|
-
const shorts: Record<string, string> = { q: "queue" };
|
|
29
|
-
const longIdx = args.indexOf(`--${name}`);
|
|
30
|
-
const shortKey = Object.entries(shorts).find(([, v]) => v === name)?.[0];
|
|
31
|
-
const shortIdx = shortKey ? args.indexOf(`-${shortKey}`) : -1;
|
|
32
|
-
const i = Math.max(longIdx, shortIdx);
|
|
33
|
-
if (i === -1 || i + 1 >= args.length) return undefined;
|
|
34
|
-
return args[i + 1];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function hasFlag(name: string): boolean {
|
|
38
|
-
return args.includes(`--${name}`);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Load config
|
|
42
|
-
const configPath = getArg("config") || "mailsend.json";
|
|
43
|
-
if (!fs.existsSync(configPath)) {
|
|
44
|
-
console.error(`Config file not found: ${configPath}`);
|
|
45
|
-
console.error(`Create a mailsend.json with baseDir, accounts, etc.`);
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const config: MailSendConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
50
|
-
const sender = initMailSend(config);
|
|
51
|
-
const accountId = getArg("queue") || config.defaultAccount || "";
|
|
52
|
-
|
|
53
|
-
// ── Queue management ──
|
|
54
|
-
|
|
55
|
-
if (hasFlag("status")) {
|
|
56
|
-
const status = sender.getStatus();
|
|
57
|
-
for (const [id, s] of Object.entries(status)) {
|
|
58
|
-
console.log(` ${id}: ${s.pending} pending, ${s.failed} failed`);
|
|
59
|
-
}
|
|
60
|
-
process.exit(0);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (hasFlag("process") && !hasFlag("new")) {
|
|
64
|
-
if (accountId && accountId !== config.defaultAccount) {
|
|
65
|
-
await sender.processQueue(accountId);
|
|
66
|
-
} else {
|
|
67
|
-
await sender.processAllQueues();
|
|
68
|
-
}
|
|
69
|
-
process.exit(0);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// ── Create new message ──
|
|
73
|
-
|
|
74
|
-
if (hasFlag("new")) {
|
|
75
|
-
let msg: Partial<MailMessage> = {};
|
|
76
|
-
|
|
77
|
-
const jsonArg = getArg("json");
|
|
78
|
-
if (jsonArg) {
|
|
79
|
-
// Load from JSON file or stdin
|
|
80
|
-
const raw = jsonArg === "-"
|
|
81
|
-
? fs.readFileSync(0, "utf-8") // stdin
|
|
82
|
-
: fs.readFileSync(jsonArg, "utf-8");
|
|
83
|
-
msg = JSON.parse(raw);
|
|
84
|
-
} else {
|
|
85
|
-
// Build from CLI args
|
|
86
|
-
const to = getArg("to");
|
|
87
|
-
if (!to) {
|
|
88
|
-
console.error("--new requires --to or --json");
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
msg = {
|
|
92
|
-
to: to.split(",").map(s => s.trim()),
|
|
93
|
-
subject: getArg("subject") || "(no subject)",
|
|
94
|
-
text: getArg("body") || "",
|
|
95
|
-
html: getArg("html"),
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Set from/account
|
|
100
|
-
const acctId = msg.accountId || accountId;
|
|
101
|
-
const acct = config.accounts[acctId];
|
|
102
|
-
if (!acct) {
|
|
103
|
-
console.error(`Unknown account: ${acctId}`);
|
|
104
|
-
console.error(`Available: ${Object.keys(config.accounts).join(", ")}`);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
msg.from = msg.from || getArg("from") || acct.from || acct.user;
|
|
109
|
-
msg.accountId = acctId;
|
|
110
|
-
|
|
111
|
-
if (!msg.to?.length) {
|
|
112
|
-
console.error("Message must have at least one recipient (to)");
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const filename = queueMessage(msg as MailMessage);
|
|
117
|
-
console.log(`Queued: ${filename}`);
|
|
118
|
-
setTimeout(() => process.exit(0), 2000);
|
|
119
|
-
} else if (!hasFlag("status") && !hasFlag("process")) {
|
|
120
|
-
console.error("Usage:");
|
|
121
|
-
console.error(" mailx-send --new --to addr --subject text [--body text] [-q account]");
|
|
122
|
-
console.error(" mailx-send --new --json message.json [-q account]");
|
|
123
|
-
console.error(" mailx-send --process [-q account]");
|
|
124
|
-
console.error(" mailx-send --status");
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @bobfrankston/mailsend
|
|
3
|
-
* Queue-based mail sender. Each account has its own queue directory.
|
|
4
|
-
* Messages queued as .ltr (RFC 822) files, sent via SMTP with retry.
|
|
5
|
-
* Supports password and OAuth2 (Gmail) authentication.
|
|
6
|
-
*
|
|
7
|
-
* Directory structure:
|
|
8
|
-
* {baseDir}/{accountId}/queue/ — pending .ltr files
|
|
9
|
-
* {baseDir}/{accountId}/sent/ — sent messages (optional, YYYY/MM/DD)
|
|
10
|
-
* {baseDir}/{accountId}/fail/ — failed messages for retry
|
|
11
|
-
*/
|
|
12
|
-
export interface SmtpConfig {
|
|
13
|
-
host: string;
|
|
14
|
-
port: number;
|
|
15
|
-
secure?: boolean;
|
|
16
|
-
auth: "password" | "oauth2";
|
|
17
|
-
user: string;
|
|
18
|
-
password?: string;
|
|
19
|
-
/** Default From address, e.g. "Bob Frankston <bob@iecc.com>" */
|
|
20
|
-
from?: string;
|
|
21
|
-
tokenProvider?: () => Promise<string>;
|
|
22
|
-
}
|
|
23
|
-
export interface MailMessage {
|
|
24
|
-
from: string;
|
|
25
|
-
to: string[];
|
|
26
|
-
cc?: string[];
|
|
27
|
-
bcc?: string[];
|
|
28
|
-
subject: string;
|
|
29
|
-
html?: string;
|
|
30
|
-
text?: string;
|
|
31
|
-
inReplyTo?: string;
|
|
32
|
-
references?: string;
|
|
33
|
-
accountId?: string;
|
|
34
|
-
}
|
|
35
|
-
export interface MailSendConfig {
|
|
36
|
-
/** Base directory for all queues */
|
|
37
|
-
baseDir: string;
|
|
38
|
-
/** SMTP configs keyed by account ID */
|
|
39
|
-
accounts: Record<string, SmtpConfig>;
|
|
40
|
-
/** Log sent messages to sent/ subdirectory */
|
|
41
|
-
logSent?: boolean;
|
|
42
|
-
/** Retry interval in ms (default: 5 minutes) */
|
|
43
|
-
retryIntervalMs?: number;
|
|
44
|
-
/** Default account ID */
|
|
45
|
-
defaultAccount?: string;
|
|
46
|
-
}
|
|
47
|
-
export declare function buildRfc822(msg: MailMessage): string;
|
|
48
|
-
export declare class MailSender {
|
|
49
|
-
private config;
|
|
50
|
-
private processing;
|
|
51
|
-
private retryTimer;
|
|
52
|
-
constructor(config: MailSendConfig);
|
|
53
|
-
private accountDir;
|
|
54
|
-
private queueDir;
|
|
55
|
-
private sentDir;
|
|
56
|
-
private failDir;
|
|
57
|
-
/** Queue a message. Returns the filename. */
|
|
58
|
-
queueMessage(msg: MailMessage): string;
|
|
59
|
-
/** Process pending messages for one account */
|
|
60
|
-
processQueue(accountId: string): Promise<void>;
|
|
61
|
-
/** Process all account queues */
|
|
62
|
-
processAllQueues(): Promise<void>;
|
|
63
|
-
private sendFile;
|
|
64
|
-
/** Start background worker — retries failed, processes queues */
|
|
65
|
-
startWorker(): void;
|
|
66
|
-
private retryFailed;
|
|
67
|
-
stopWorker(): void;
|
|
68
|
-
/** Get queue status per account */
|
|
69
|
-
getStatus(): Record<string, {
|
|
70
|
-
pending: number;
|
|
71
|
-
failed: number;
|
|
72
|
-
}>;
|
|
73
|
-
}
|
|
74
|
-
export declare function initMailSend(config: MailSendConfig): MailSender;
|
|
75
|
-
export declare function getMailSender(): MailSender | null;
|
|
76
|
-
export declare function queueMessage(msg: MailMessage): string;
|
|
77
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AASH,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC3B,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yBAAyB;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAoDD,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CA8BpD;AAiCD,qBAAa,UAAU;IACnB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAA+C;gBAErD,MAAM,EAAE,cAAc;IAMlC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAMf,6CAA6C;IAC7C,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM;IAiBtC,+CAA+C;IACzC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBpD,iCAAiC;IAC3B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;YAMzB,QAAQ;IAkCtB,iEAAiE;IACjE,WAAW,IAAI,IAAI;IAYnB,OAAO,CAAC,WAAW;IAQnB,UAAU,IAAI,IAAI;IAOlB,mCAAmC;IACnC,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAUnE;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,UAAU,CAI/D;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAGrD"}
|
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @bobfrankston/mailsend
|
|
3
|
-
* Queue-based mail sender. Each account has its own queue directory.
|
|
4
|
-
* Messages queued as .ltr (RFC 822) files, sent via SMTP with retry.
|
|
5
|
-
* Supports password and OAuth2 (Gmail) authentication.
|
|
6
|
-
*
|
|
7
|
-
* Directory structure:
|
|
8
|
-
* {baseDir}/{accountId}/queue/ — pending .ltr files
|
|
9
|
-
* {baseDir}/{accountId}/sent/ — sent messages (optional, YYYY/MM/DD)
|
|
10
|
-
* {baseDir}/{accountId}/fail/ — failed messages for retry
|
|
11
|
-
*/
|
|
12
|
-
import * as fs from "node:fs";
|
|
13
|
-
import * as path from "node:path";
|
|
14
|
-
import { createTransport } from "nodemailer";
|
|
15
|
-
import { encodeHeaderWord, encodeAddressHeader } from "@bobfrankston/mailx-types";
|
|
16
|
-
// ── File helpers ──
|
|
17
|
-
function generateFilename() {
|
|
18
|
-
const now = new Date();
|
|
19
|
-
const pad2 = (n) => String(n).padStart(2, "0");
|
|
20
|
-
const ts = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}_${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
|
|
21
|
-
const seq = String(Math.floor(Math.random() * 10000)).padStart(4, "0");
|
|
22
|
-
return `${ts}-${seq}.ltr`;
|
|
23
|
-
}
|
|
24
|
-
function datePath() {
|
|
25
|
-
const dt = new Date();
|
|
26
|
-
const pad2 = (n) => String(n).padStart(2, "0");
|
|
27
|
-
return `${dt.getFullYear()}/${pad2(dt.getMonth() + 1)}/${pad2(dt.getDate())}`;
|
|
28
|
-
}
|
|
29
|
-
function moveToDateDir(filePath, destBase) {
|
|
30
|
-
const dest = path.join(destBase, datePath());
|
|
31
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
32
|
-
fs.renameSync(filePath, path.join(dest, path.basename(filePath)));
|
|
33
|
-
}
|
|
34
|
-
function listLtr(dir) {
|
|
35
|
-
if (!fs.existsSync(dir))
|
|
36
|
-
return [];
|
|
37
|
-
return fs.readdirSync(dir).filter(f => f.endsWith(".ltr")).sort();
|
|
38
|
-
}
|
|
39
|
-
function walkLtrCount(dir) {
|
|
40
|
-
if (!fs.existsSync(dir))
|
|
41
|
-
return 0;
|
|
42
|
-
let count = 0;
|
|
43
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
44
|
-
if (entry.isDirectory())
|
|
45
|
-
count += walkLtrCount(path.join(dir, entry.name));
|
|
46
|
-
else if (entry.name.endsWith(".ltr"))
|
|
47
|
-
count++;
|
|
48
|
-
}
|
|
49
|
-
return count;
|
|
50
|
-
}
|
|
51
|
-
function walkLtrFiles(dir) {
|
|
52
|
-
if (!fs.existsSync(dir))
|
|
53
|
-
return [];
|
|
54
|
-
const files = [];
|
|
55
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
56
|
-
const full = path.join(dir, entry.name);
|
|
57
|
-
if (entry.isDirectory())
|
|
58
|
-
files.push(...walkLtrFiles(full));
|
|
59
|
-
else if (entry.name.endsWith(".ltr"))
|
|
60
|
-
files.push(full);
|
|
61
|
-
}
|
|
62
|
-
return files;
|
|
63
|
-
}
|
|
64
|
-
// ── RFC 822 builder ──
|
|
65
|
-
export function buildRfc822(msg) {
|
|
66
|
-
const lines = [];
|
|
67
|
-
// RFC 2047-encode anything non-ASCII. Raw 8-bit here makes the whole
|
|
68
|
-
// message EAI (RFC 6530) and it bounces from every receiver without
|
|
69
|
-
// SMTPUTF8 — one curly apostrophe in a reply subject was enough
|
|
70
|
-
// (Bob 2026-08-08, gal.iecc.com bounce).
|
|
71
|
-
lines.push(`From: ${encodeAddressHeader(msg.from)}`);
|
|
72
|
-
lines.push(`To: ${encodeAddressHeader(msg.to.join(", "))}`);
|
|
73
|
-
if (msg.cc?.length)
|
|
74
|
-
lines.push(`Cc: ${encodeAddressHeader(msg.cc.join(", "))}`);
|
|
75
|
-
if (msg.bcc?.length)
|
|
76
|
-
lines.push(`Bcc: ${encodeAddressHeader(msg.bcc.join(", "))}`);
|
|
77
|
-
lines.push(`Subject: ${encodeHeaderWord(msg.subject)}`);
|
|
78
|
-
lines.push(`Date: ${new Date().toUTCString()}`);
|
|
79
|
-
if (msg.inReplyTo)
|
|
80
|
-
lines.push(`In-Reply-To: ${msg.inReplyTo}`);
|
|
81
|
-
if (msg.references)
|
|
82
|
-
lines.push(`References: ${msg.references}`);
|
|
83
|
-
if (msg.accountId)
|
|
84
|
-
lines.push(`X-MailSend-Account: ${msg.accountId}`);
|
|
85
|
-
lines.push(`MIME-Version: 1.0`);
|
|
86
|
-
if (msg.html) {
|
|
87
|
-
lines.push(`Content-Type: text/html; charset=UTF-8`);
|
|
88
|
-
lines.push(`Content-Transfer-Encoding: 8bit`);
|
|
89
|
-
lines.push("");
|
|
90
|
-
lines.push(msg.html);
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
lines.push(`Content-Type: text/plain; charset=UTF-8`);
|
|
94
|
-
lines.push(`Content-Transfer-Encoding: 8bit`);
|
|
95
|
-
lines.push("");
|
|
96
|
-
lines.push(msg.text || "");
|
|
97
|
-
}
|
|
98
|
-
return lines.join("\r\n");
|
|
99
|
-
}
|
|
100
|
-
// ── Transport cache ──
|
|
101
|
-
const transports = new Map();
|
|
102
|
-
function getTransport(config) {
|
|
103
|
-
const key = `${config.host}:${config.port}:${config.user}`;
|
|
104
|
-
let transport = transports.get(key);
|
|
105
|
-
if (!transport) {
|
|
106
|
-
const opts = {
|
|
107
|
-
host: config.host,
|
|
108
|
-
port: config.port,
|
|
109
|
-
secure: config.secure ?? (config.port === 465),
|
|
110
|
-
tls: { rejectUnauthorized: false },
|
|
111
|
-
};
|
|
112
|
-
if (config.auth === "password") {
|
|
113
|
-
opts.auth = { user: config.user, pass: config.password };
|
|
114
|
-
}
|
|
115
|
-
else if (config.auth === "oauth2") {
|
|
116
|
-
opts.auth = { type: "OAuth2", user: config.user };
|
|
117
|
-
}
|
|
118
|
-
transport = createTransport(opts);
|
|
119
|
-
transports.set(key, transport);
|
|
120
|
-
}
|
|
121
|
-
return transport;
|
|
122
|
-
}
|
|
123
|
-
// ── MailSender ──
|
|
124
|
-
let singleton = null;
|
|
125
|
-
export class MailSender {
|
|
126
|
-
config;
|
|
127
|
-
processing = false;
|
|
128
|
-
retryTimer = null;
|
|
129
|
-
constructor(config) {
|
|
130
|
-
this.config = config;
|
|
131
|
-
// Ensure base directory exists
|
|
132
|
-
fs.mkdirSync(config.baseDir, { recursive: true });
|
|
133
|
-
}
|
|
134
|
-
accountDir(accountId) {
|
|
135
|
-
return path.join(this.config.baseDir, accountId);
|
|
136
|
-
}
|
|
137
|
-
queueDir(accountId) {
|
|
138
|
-
const dir = path.join(this.accountDir(accountId), "queue");
|
|
139
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
140
|
-
return dir;
|
|
141
|
-
}
|
|
142
|
-
sentDir(accountId) {
|
|
143
|
-
return path.join(this.accountDir(accountId), "sent");
|
|
144
|
-
}
|
|
145
|
-
failDir(accountId) {
|
|
146
|
-
const dir = path.join(this.accountDir(accountId), "fail");
|
|
147
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
148
|
-
return dir;
|
|
149
|
-
}
|
|
150
|
-
/** Queue a message. Returns the filename. */
|
|
151
|
-
queueMessage(msg) {
|
|
152
|
-
const accountId = msg.accountId || this.config.defaultAccount;
|
|
153
|
-
if (!accountId)
|
|
154
|
-
throw new Error("No accountId and no defaultAccount configured");
|
|
155
|
-
msg.accountId = accountId;
|
|
156
|
-
const content = buildRfc822(msg);
|
|
157
|
-
const filename = generateFilename();
|
|
158
|
-
fs.writeFileSync(path.join(this.queueDir(accountId), filename), content);
|
|
159
|
-
// Process immediately (non-blocking)
|
|
160
|
-
this.processQueue(accountId).catch(e => console.error(`[mailsend] Process error: ${e.message}`));
|
|
161
|
-
return filename;
|
|
162
|
-
}
|
|
163
|
-
/** Process pending messages for one account */
|
|
164
|
-
async processQueue(accountId) {
|
|
165
|
-
if (this.processing)
|
|
166
|
-
return;
|
|
167
|
-
this.processing = true;
|
|
168
|
-
try {
|
|
169
|
-
const smtpConfig = this.config.accounts[accountId];
|
|
170
|
-
if (!smtpConfig) {
|
|
171
|
-
console.error(`[mailsend] No SMTP config for: ${accountId}`);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const files = listLtr(this.queueDir(accountId));
|
|
175
|
-
for (const file of files) {
|
|
176
|
-
await this.sendFile(path.join(this.queueDir(accountId), file), accountId, smtpConfig);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
finally {
|
|
180
|
-
this.processing = false;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
/** Process all account queues */
|
|
184
|
-
async processAllQueues() {
|
|
185
|
-
for (const accountId of Object.keys(this.config.accounts)) {
|
|
186
|
-
await this.processQueue(accountId);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
async sendFile(filePath, accountId, smtpConfig) {
|
|
190
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
191
|
-
try {
|
|
192
|
-
const transport = getTransport(smtpConfig);
|
|
193
|
-
if (smtpConfig.auth === "oauth2" && smtpConfig.tokenProvider) {
|
|
194
|
-
const token = await smtpConfig.tokenProvider();
|
|
195
|
-
transport.options.auth.accessToken = token;
|
|
196
|
-
}
|
|
197
|
-
const result = await transport.sendMail({ raw: content });
|
|
198
|
-
if (result.rejected?.length > 0) {
|
|
199
|
-
console.error(`[mailsend] Rejected: ${result.rejected.join(", ")} — ${path.basename(filePath)}`);
|
|
200
|
-
moveToDateDir(filePath, this.failDir(accountId));
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
console.log(`[mailsend] Sent: ${path.basename(filePath)} → ${result.accepted?.join(", ")} (${result.messageId})`);
|
|
204
|
-
if (this.config.logSent) {
|
|
205
|
-
moveToDateDir(filePath, this.sentDir(accountId));
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
fs.unlinkSync(filePath);
|
|
209
|
-
}
|
|
210
|
-
return true;
|
|
211
|
-
}
|
|
212
|
-
catch (e) {
|
|
213
|
-
console.error(`[mailsend] Error: ${path.basename(filePath)}: ${e.message}`);
|
|
214
|
-
moveToDateDir(filePath, this.failDir(accountId));
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
/** Start background worker — retries failed, processes queues */
|
|
219
|
-
startWorker() {
|
|
220
|
-
if (this.retryTimer)
|
|
221
|
-
return;
|
|
222
|
-
const interval = this.config.retryIntervalMs || 300000;
|
|
223
|
-
this.retryTimer = setInterval(async () => {
|
|
224
|
-
for (const accountId of Object.keys(this.config.accounts)) {
|
|
225
|
-
this.retryFailed(accountId);
|
|
226
|
-
}
|
|
227
|
-
await this.processAllQueues();
|
|
228
|
-
}, interval);
|
|
229
|
-
}
|
|
230
|
-
retryFailed(accountId) {
|
|
231
|
-
const failFiles = walkLtrFiles(this.failDir(accountId));
|
|
232
|
-
const queueDir = this.queueDir(accountId);
|
|
233
|
-
for (const file of failFiles) {
|
|
234
|
-
fs.renameSync(file, path.join(queueDir, path.basename(file)));
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
stopWorker() {
|
|
238
|
-
if (this.retryTimer) {
|
|
239
|
-
clearInterval(this.retryTimer);
|
|
240
|
-
this.retryTimer = null;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/** Get queue status per account */
|
|
244
|
-
getStatus() {
|
|
245
|
-
const result = {};
|
|
246
|
-
for (const accountId of Object.keys(this.config.accounts)) {
|
|
247
|
-
result[accountId] = {
|
|
248
|
-
pending: listLtr(this.queueDir(accountId)).length,
|
|
249
|
-
failed: walkLtrCount(this.failDir(accountId)),
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
// ── Singleton API ──
|
|
256
|
-
export function initMailSend(config) {
|
|
257
|
-
singleton = new MailSender(config);
|
|
258
|
-
singleton.startWorker();
|
|
259
|
-
return singleton;
|
|
260
|
-
}
|
|
261
|
-
export function getMailSender() {
|
|
262
|
-
return singleton;
|
|
263
|
-
}
|
|
264
|
-
export function queueMessage(msg) {
|
|
265
|
-
if (!singleton)
|
|
266
|
-
throw new Error("mailsend not initialized — call initMailSend() first");
|
|
267
|
-
return singleton.queueMessage(msg);
|
|
268
|
-
}
|
|
269
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|