mailchannels-sdk 1.3.1 → 1.4.0
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/.agents/skills/mailchannels-js/SKILL.md +4 -0
- package/.agents/skills/mailchannels-js/resources/attachments.md +7 -7
- package/.agents/skills/mailchannels-js/resources/clients-and-transport.md +5 -5
- package/.agents/skills/mailchannels-js/resources/custom-headers.md +4 -4
- package/.agents/skills/mailchannels-js/resources/dkim.md +10 -10
- package/.agents/skills/mailchannels-js/resources/domain-checks.md +6 -6
- package/.agents/skills/mailchannels-js/resources/error-handling.md +5 -5
- package/.agents/skills/mailchannels-js/resources/metrics-and-usage.md +9 -9
- package/.agents/skills/mailchannels-js/resources/overview.md +5 -5
- package/.agents/skills/mailchannels-js/resources/plugins/nodemailer.md +112 -0
- package/.agents/skills/mailchannels-js/resources/sending.md +10 -10
- package/.agents/skills/mailchannels-js/resources/sub-accounts.md +7 -7
- package/.agents/skills/mailchannels-js/resources/suppressions.md +4 -4
- package/.agents/skills/mailchannels-js/resources/templates.md +5 -5
- package/.agents/skills/mailchannels-js/resources/testing.md +52 -5
- package/.agents/skills/mailchannels-js/resources/unsubscribe.md +3 -3
- package/.agents/skills/mailchannels-js/resources/webhooks.md +8 -8
- package/README.md +71 -0
- package/dist/_chunks/mailchannels.d.mts +2094 -0
- package/dist/_chunks/mailchannels.mjs +2201 -0
- package/dist/_chunks/{simulate.mjs → simulator.mjs} +7 -39
- package/dist/cli/index.mjs +266 -13
- package/dist/mailchannels.d.mts +1 -2093
- package/dist/mailchannels.mjs +1 -2199
- package/dist/plugins/nodemailer/index.d.mts +33 -0
- package/dist/plugins/nodemailer/index.mjs +145 -0
- package/dist/simulator/index.d.mts +20 -0
- package/dist/simulator/index.mjs +2 -0
- package/package.json +18 -6
- package/dist/cli/index.d.mts +0 -1
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
|
-
import { parseArgs } from "node:util";
|
|
3
2
|
import { createServer } from "node:http";
|
|
4
3
|
const SIMULATOR_SIGNING_KEY_ID = "simulator-default";
|
|
5
4
|
const JSON_HEADERS = { "content-type": "application/json" };
|
|
@@ -798,7 +797,7 @@ const DEFAULT_PORT = 8787;
|
|
|
798
797
|
const createSimulator = (options = {}) => {
|
|
799
798
|
const { host = DEFAULT_HOST, port = DEFAULT_PORT } = options;
|
|
800
799
|
if (port !== void 0 && (isNaN(port) || port < 0 || port > 65535)) {
|
|
801
|
-
console.error(
|
|
800
|
+
console.error(`[Simulator] Invalid port '${port}': must be an integer between 0 and 65535.`);
|
|
802
801
|
process.exit(1);
|
|
803
802
|
}
|
|
804
803
|
const logRequests = !options.silent;
|
|
@@ -824,6 +823,7 @@ const createSimulator = (options = {}) => {
|
|
|
824
823
|
},
|
|
825
824
|
async close() {
|
|
826
825
|
await new Promise((resolve, reject) => {
|
|
826
|
+
console.info("[Simulator] Shutting down simulator...");
|
|
827
827
|
for (const socket of sockets) socket.destroy();
|
|
828
828
|
server.close((error) => error ? reject(error) : resolve());
|
|
829
829
|
});
|
|
@@ -840,47 +840,15 @@ const createSimulator = (options = {}) => {
|
|
|
840
840
|
server.off("error", onError);
|
|
841
841
|
resolve();
|
|
842
842
|
});
|
|
843
|
+
}).catch((error) => {
|
|
844
|
+
console.error(`[Simulator] ${error.message}`);
|
|
845
|
+
process.exit(1);
|
|
843
846
|
});
|
|
844
847
|
const address = server.address();
|
|
845
848
|
serverUrl = `http://${nextHost}:${typeof address === "object" && address ? address.port : nextPort}`;
|
|
846
|
-
if (logRequests) console.info(
|
|
849
|
+
if (logRequests) console.info(`[Simulator] listening on ${serverUrl}`);
|
|
847
850
|
return serverUrl;
|
|
848
851
|
}
|
|
849
852
|
};
|
|
850
853
|
};
|
|
851
|
-
|
|
852
|
-
const { MAILCHANNELS_SIMULATOR_PORT, MAILCHANNELS_SIMULATOR_HOST } = process.env;
|
|
853
|
-
const { values } = parseArgs({
|
|
854
|
-
args,
|
|
855
|
-
options: {
|
|
856
|
-
port: {
|
|
857
|
-
type: "string",
|
|
858
|
-
short: "p",
|
|
859
|
-
default: MAILCHANNELS_SIMULATOR_PORT
|
|
860
|
-
},
|
|
861
|
-
host: {
|
|
862
|
-
type: "string",
|
|
863
|
-
short: "h",
|
|
864
|
-
default: MAILCHANNELS_SIMULATOR_HOST
|
|
865
|
-
},
|
|
866
|
-
silent: {
|
|
867
|
-
type: "boolean",
|
|
868
|
-
short: "s",
|
|
869
|
-
default: false
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
});
|
|
873
|
-
const simulator = createSimulator({
|
|
874
|
-
host: values.host,
|
|
875
|
-
port: values.port !== void 0 ? Number.parseInt(values.port, 10) : void 0,
|
|
876
|
-
silent: values.silent
|
|
877
|
-
});
|
|
878
|
-
await simulator.listen();
|
|
879
|
-
const shutdown = async () => {
|
|
880
|
-
await simulator.close();
|
|
881
|
-
process.exit(0);
|
|
882
|
-
};
|
|
883
|
-
process.on("SIGINT", shutdown);
|
|
884
|
-
process.on("SIGTERM", shutdown);
|
|
885
|
-
};
|
|
886
|
-
export { simulate_default as default };
|
|
854
|
+
export { createSimulator };
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,15 +1,268 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
2
|
+
import { Attachment, Emails, MailChannelsClient, name, version } from "../_chunks/mailchannels.mjs";
|
|
3
|
+
import { createSimulator } from "../_chunks/simulator.mjs";
|
|
4
|
+
import { defineCommand, runMain } from "citty";
|
|
5
|
+
var simulate_default = defineCommand({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "simulate",
|
|
8
|
+
description: "Start a local MailChannels simulator server"
|
|
9
|
+
},
|
|
10
|
+
args: {
|
|
11
|
+
port: {
|
|
12
|
+
type: "string",
|
|
13
|
+
alias: "p"
|
|
14
|
+
},
|
|
15
|
+
host: {
|
|
16
|
+
type: "string",
|
|
17
|
+
alias: "h"
|
|
18
|
+
},
|
|
19
|
+
silent: {
|
|
20
|
+
type: "boolean",
|
|
21
|
+
alias: "s",
|
|
22
|
+
default: false
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
async run({ args }) {
|
|
26
|
+
const { MAILCHANNELS_SIMULATOR_HOST, MAILCHANNELS_SIMULATOR_PORT } = process.env;
|
|
27
|
+
const host = args.host || MAILCHANNELS_SIMULATOR_HOST;
|
|
28
|
+
const port = args.port || MAILCHANNELS_SIMULATOR_PORT;
|
|
29
|
+
const simulator = createSimulator({
|
|
30
|
+
host,
|
|
31
|
+
port: port !== void 0 ? Number.parseInt(port, 10) : void 0,
|
|
32
|
+
silent: args.silent
|
|
33
|
+
});
|
|
34
|
+
await simulator.listen();
|
|
35
|
+
const shutdown = async () => {
|
|
36
|
+
await simulator.close();
|
|
37
|
+
};
|
|
38
|
+
process.on("SIGINT", shutdown);
|
|
39
|
+
process.on("SIGTERM", shutdown);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const emailArgs = {
|
|
43
|
+
"api-key": {
|
|
44
|
+
type: "string",
|
|
45
|
+
alias: "k"
|
|
46
|
+
},
|
|
47
|
+
"campaign-id": { type: "string" },
|
|
48
|
+
"dkim-domain": { type: "string" },
|
|
49
|
+
"dkim-selector": { type: "string" },
|
|
50
|
+
"dkim-private-key": { type: "string" },
|
|
51
|
+
"envelope-from": { type: "string" },
|
|
52
|
+
"tracking-click": {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
default: false
|
|
55
|
+
},
|
|
56
|
+
"tracking-click-custom-domain-name": {
|
|
57
|
+
type: "string",
|
|
58
|
+
valueHint: "name"
|
|
59
|
+
},
|
|
60
|
+
"tracking-open": {
|
|
61
|
+
type: "boolean",
|
|
62
|
+
default: false
|
|
63
|
+
},
|
|
64
|
+
"tracking-open-custom-domain-name": {
|
|
65
|
+
type: "string",
|
|
66
|
+
valueHint: "name"
|
|
67
|
+
},
|
|
68
|
+
"from": {
|
|
69
|
+
type: "string",
|
|
70
|
+
required: true
|
|
71
|
+
},
|
|
72
|
+
"headers": {
|
|
73
|
+
type: "string",
|
|
74
|
+
alias: "h",
|
|
75
|
+
valueHint: "JSON"
|
|
76
|
+
},
|
|
77
|
+
"to": {
|
|
78
|
+
type: "string",
|
|
79
|
+
required: true
|
|
80
|
+
},
|
|
81
|
+
"subject": {
|
|
82
|
+
type: "string",
|
|
83
|
+
required: true
|
|
84
|
+
},
|
|
85
|
+
"text": {
|
|
86
|
+
type: "string",
|
|
87
|
+
default: ""
|
|
88
|
+
},
|
|
89
|
+
"html": {
|
|
90
|
+
type: "string",
|
|
91
|
+
default: ""
|
|
92
|
+
},
|
|
93
|
+
"cc": { type: "string" },
|
|
94
|
+
"bcc": { type: "string" },
|
|
95
|
+
"reply-to": { type: "string" },
|
|
96
|
+
"attachments": {
|
|
97
|
+
type: "boolean",
|
|
98
|
+
alias: "a",
|
|
99
|
+
default: false
|
|
100
|
+
},
|
|
101
|
+
"transactional": {
|
|
102
|
+
type: "boolean",
|
|
103
|
+
default: true
|
|
104
|
+
},
|
|
105
|
+
"unsubscribe-custom-domain-name": {
|
|
106
|
+
type: "string",
|
|
107
|
+
valueHint: "name"
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const getApiKey = (apiKey) => {
|
|
111
|
+
const { MAILCHANNELS_API_KEY } = process.env;
|
|
112
|
+
const key = MAILCHANNELS_API_KEY || apiKey;
|
|
113
|
+
if (!key) {
|
|
114
|
+
console.error("[Emails] Missing API key. Provide it using the '--api-key' flag or set the 'MAILCHANNELS_API_KEY' environment variable.");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
return key;
|
|
118
|
+
};
|
|
119
|
+
const parseAttachments = async (rawAttachments) => {
|
|
120
|
+
if (!rawAttachments) return;
|
|
121
|
+
if (process.stdin.isTTY) {
|
|
122
|
+
console.error("[Emails] '--attachments' requires JSON input piped to stdin.");
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
let input = "";
|
|
126
|
+
for await (const chunk of process.stdin) input += chunk;
|
|
127
|
+
let inputAttachments = [];
|
|
128
|
+
try {
|
|
129
|
+
inputAttachments = JSON.parse(input);
|
|
130
|
+
} catch {
|
|
131
|
+
console.error("[Emails] JSON input for '--attachments' is not valid.");
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
return inputAttachments.map((attachment, index) => {
|
|
135
|
+
if (!attachment.content || !attachment.filename) {
|
|
136
|
+
console.error("[Emails] Attachment at index " + index + " is missing required fields 'content' or 'filename'.");
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
if (attachment.type) return {
|
|
140
|
+
content: attachment.content,
|
|
141
|
+
filename: attachment.filename,
|
|
142
|
+
type: attachment.type,
|
|
143
|
+
contentId: attachment.content_id
|
|
144
|
+
};
|
|
145
|
+
return Attachment.fromBytes(Buffer.from(attachment.content, "base64"), {
|
|
146
|
+
filename: attachment.filename,
|
|
147
|
+
type: attachment.type,
|
|
148
|
+
contentId: attachment.content_id
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
const parseHeaders = (rawHeaders) => {
|
|
153
|
+
if (!rawHeaders) return;
|
|
154
|
+
try {
|
|
155
|
+
return JSON.parse(rawHeaders);
|
|
156
|
+
} catch {
|
|
157
|
+
console.error("[Emails] Invalid JSON for '--headers'");
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const parseOptions = async (args) => {
|
|
162
|
+
const attachments = await parseAttachments(args["attachments"]);
|
|
163
|
+
const headers = parseHeaders(args["headers"]);
|
|
164
|
+
return {
|
|
165
|
+
attachments,
|
|
166
|
+
campaignId: args["campaign-id"],
|
|
167
|
+
dkim: {
|
|
168
|
+
domain: args["dkim-domain"],
|
|
169
|
+
selector: args["dkim-selector"],
|
|
170
|
+
privateKey: args["dkim-private-key"]
|
|
171
|
+
},
|
|
172
|
+
envelopeFrom: args["envelope-from"],
|
|
173
|
+
tracking: {
|
|
174
|
+
click: {
|
|
175
|
+
customDomainName: args["tracking-click-custom-domain-name"],
|
|
176
|
+
enable: args["tracking-click"] || Boolean(args["tracking-click-custom-domain-name"])
|
|
177
|
+
},
|
|
178
|
+
open: {
|
|
179
|
+
customDomainName: args["tracking-open-custom-domain-name"],
|
|
180
|
+
enable: args["tracking-open"] || Boolean(args["tracking-open-custom-domain-name"])
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
headers,
|
|
184
|
+
from: args["from"],
|
|
185
|
+
to: args["to"].split(",").map((r) => r.trim()),
|
|
186
|
+
subject: args["subject"],
|
|
187
|
+
cc: args["cc"]?.split(",").map((r) => r.trim()),
|
|
188
|
+
bcc: args["bcc"]?.split(",").map((r) => r.trim()),
|
|
189
|
+
replyTo: args["reply-to"],
|
|
190
|
+
html: args["html"],
|
|
191
|
+
text: args["text"],
|
|
192
|
+
transactional: args["transactional"],
|
|
193
|
+
unsubscribe: { customDomainName: args["unsubscribe-custom-domain-name"] }
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
var send_default = defineCommand({
|
|
197
|
+
meta: {
|
|
198
|
+
name: "send",
|
|
199
|
+
description: "Send an email using the MailChannels Email API"
|
|
200
|
+
},
|
|
201
|
+
args: {
|
|
202
|
+
...emailArgs,
|
|
203
|
+
"dry-run": {
|
|
204
|
+
type: "boolean",
|
|
205
|
+
default: false
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
async run({ args }) {
|
|
209
|
+
const apiKey = getApiKey(args["api-key"]);
|
|
210
|
+
const client = new MailChannelsClient(apiKey);
|
|
211
|
+
const emails = new Emails(client);
|
|
212
|
+
const sendOptions = await parseOptions(args);
|
|
213
|
+
const { error } = await emails.send(sendOptions, args["dry-run"]);
|
|
214
|
+
if (error) {
|
|
215
|
+
console.error(`[Emails] ${error.message}`);
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
console.info("[Emails] Email sent successfully.");
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
var queue_default = defineCommand({
|
|
222
|
+
meta: {
|
|
223
|
+
name: "queue",
|
|
224
|
+
description: "Queue an email to be sent using the MailChannels Email API"
|
|
225
|
+
},
|
|
226
|
+
args: emailArgs,
|
|
227
|
+
async run({ args }) {
|
|
228
|
+
const apiKey = getApiKey(args["api-key"]);
|
|
229
|
+
const client = new MailChannelsClient(apiKey);
|
|
230
|
+
const emails = new Emails(client);
|
|
231
|
+
const sendOptions = await parseOptions(args);
|
|
232
|
+
const { error } = await emails.queue(sendOptions);
|
|
233
|
+
if (error) {
|
|
234
|
+
console.error(`[Emails] ${error.message}`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
console.info("[Emails] Email queued successfully.");
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
var emails_default = defineCommand({
|
|
241
|
+
meta: {
|
|
242
|
+
name: "emails",
|
|
243
|
+
description: "Commands for sending emails using the MailChannels Email API"
|
|
244
|
+
},
|
|
245
|
+
args: {},
|
|
246
|
+
subCommands: {
|
|
247
|
+
send: send_default,
|
|
248
|
+
queue: queue_default
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
const main = defineCommand({
|
|
252
|
+
meta: {
|
|
253
|
+
name,
|
|
254
|
+
description: "MailChannels CLI",
|
|
255
|
+
version
|
|
256
|
+
},
|
|
257
|
+
subCommands: {
|
|
258
|
+
simulate: simulate_default,
|
|
259
|
+
emails: emails_default
|
|
260
|
+
},
|
|
261
|
+
setup() {
|
|
262
|
+
const LOGGER_NAME = "[MailChannels-CLI]";
|
|
263
|
+
console.info = console.info.bind(console, LOGGER_NAME);
|
|
264
|
+
console.error = console.error.bind(console, LOGGER_NAME);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
runMain(main);
|
|
15
268
|
export {};
|