mailchannels-sdk 1.5.2 → 1.6.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/README.md +3 -3
- package/dist/_chunks/mailchannels.d.mts +126 -122
- package/dist/_chunks/mailchannels.mjs +87 -15
- package/dist/plugins/nodemailer/index.d.mts +10 -8
- package/dist/plugins/nodemailer/index.mjs +9 -4
- package/dist/simulator/index.d.mts +2 -3
- package/package.json +9 -10
- package/CHANGELOG.md +0 -1572
|
@@ -3,7 +3,7 @@ import { subtle } from "node:crypto";
|
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
4
|
import mime from "mime";
|
|
5
5
|
var name = "mailchannels-sdk";
|
|
6
|
-
var version = "1.
|
|
6
|
+
var version = "1.6.0";
|
|
7
7
|
var MailChannelsClient = class MailChannelsClient {
|
|
8
8
|
static DEFAULT_BASE_URL = "https://api.mailchannels.net";
|
|
9
9
|
static DEFAULT_TIMEOUT = 12e4;
|
|
@@ -114,8 +114,14 @@ const createValidationError = (message) => {
|
|
|
114
114
|
};
|
|
115
115
|
const validatePagination = (pagination = {}) => {
|
|
116
116
|
const { limit, offset, max } = pagination;
|
|
117
|
-
if (
|
|
118
|
-
|
|
117
|
+
if (limit !== void 0) {
|
|
118
|
+
if (!Number.isInteger(limit)) return createValidationError("The limit value must be an integer.");
|
|
119
|
+
if (limit < 1 || max != null && limit > max) return createValidationError("The limit value " + (max != null ? `must be between 1 and ${max}.` : "is invalid. Only positive values are allowed."));
|
|
120
|
+
}
|
|
121
|
+
if (offset !== void 0) {
|
|
122
|
+
if (!Number.isInteger(offset)) return createValidationError("The offset value must be an integer.");
|
|
123
|
+
if (offset < 0) return createValidationError("The offset value must be greater than or equal to 0.");
|
|
124
|
+
}
|
|
119
125
|
return null;
|
|
120
126
|
};
|
|
121
127
|
const CUSTOM_TRACKING_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
@@ -458,8 +464,17 @@ const mapDkimKey = (key) => ({
|
|
|
458
464
|
status: key.status,
|
|
459
465
|
statusModifiedAt: key.status_modified_at
|
|
460
466
|
});
|
|
461
|
-
|
|
467
|
+
const quoteValues = (values) => {
|
|
468
|
+
return Array.from(values).map((value) => `'${value}'`).join(", ");
|
|
469
|
+
};
|
|
470
|
+
var DomainsDkim = class DomainsDkim {
|
|
462
471
|
mailchannels;
|
|
472
|
+
static UPDATE_STATUS_VALUES = /* @__PURE__ */ new Set([
|
|
473
|
+
"retired",
|
|
474
|
+
"revoked",
|
|
475
|
+
"rotated"
|
|
476
|
+
]);
|
|
477
|
+
static STATUS_VALUES = /* @__PURE__ */ new Set(["active", ...DomainsDkim.UPDATE_STATUS_VALUES]);
|
|
463
478
|
constructor(mailchannels) {
|
|
464
479
|
this.mailchannels = mailchannels;
|
|
465
480
|
}
|
|
@@ -518,6 +533,13 @@ var DomainsDkim = class {
|
|
|
518
533
|
error
|
|
519
534
|
};
|
|
520
535
|
}
|
|
536
|
+
if (options?.status !== void 0 && !DomainsDkim.STATUS_VALUES.has(options.status)) {
|
|
537
|
+
error = createValidationError(`Status must be one of ${quoteValues(DomainsDkim.STATUS_VALUES)}.`);
|
|
538
|
+
return {
|
|
539
|
+
data: null,
|
|
540
|
+
error
|
|
541
|
+
};
|
|
542
|
+
}
|
|
521
543
|
error = validatePagination({
|
|
522
544
|
...options,
|
|
523
545
|
max: 100
|
|
@@ -567,6 +589,13 @@ var DomainsDkim = class {
|
|
|
567
589
|
error
|
|
568
590
|
};
|
|
569
591
|
}
|
|
592
|
+
if (options?.status !== void 0 && !DomainsDkim.UPDATE_STATUS_VALUES.has(options.status)) {
|
|
593
|
+
error = createValidationError(`Status must be one of ${quoteValues(DomainsDkim.UPDATE_STATUS_VALUES)}.`);
|
|
594
|
+
return {
|
|
595
|
+
success: false,
|
|
596
|
+
error
|
|
597
|
+
};
|
|
598
|
+
}
|
|
570
599
|
const payload = { status: options.status };
|
|
571
600
|
await this.mailchannels.patch(`/tx/v1/domains/${encodeURIComponent(domain)}/dkim-keys/${encodeURIComponent(options.selector)}`, {
|
|
572
601
|
body: payload,
|
|
@@ -760,7 +789,7 @@ var DomainsCustomTracking = class DomainsCustomTracking {
|
|
|
760
789
|
};
|
|
761
790
|
}
|
|
762
791
|
if (!scope || !DomainsCustomTracking.SCOPE_VALUES.has(scope)) {
|
|
763
|
-
error = createValidationError(
|
|
792
|
+
error = createValidationError(`Scope must be one of ${quoteValues(DomainsCustomTracking.SCOPE_VALUES)}.`);
|
|
764
793
|
return {
|
|
765
794
|
data: null,
|
|
766
795
|
error
|
|
@@ -1036,6 +1065,14 @@ const parseDateInputs = (options) => {
|
|
|
1036
1065
|
};
|
|
1037
1066
|
var Webhooks = class Webhooks {
|
|
1038
1067
|
mailchannels;
|
|
1068
|
+
static STATUS_VALUES = /* @__PURE__ */ new Set([
|
|
1069
|
+
"1xx",
|
|
1070
|
+
"2xx",
|
|
1071
|
+
"3xx",
|
|
1072
|
+
"4xx",
|
|
1073
|
+
"5xx",
|
|
1074
|
+
"no_response"
|
|
1075
|
+
]);
|
|
1039
1076
|
constructor(mailchannels) {
|
|
1040
1077
|
this.mailchannels = mailchannels;
|
|
1041
1078
|
}
|
|
@@ -1207,14 +1244,27 @@ var Webhooks = class Webhooks {
|
|
|
1207
1244
|
data: null,
|
|
1208
1245
|
error
|
|
1209
1246
|
};
|
|
1210
|
-
if (options?.statuses
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1247
|
+
if (options?.statuses !== void 0) {
|
|
1248
|
+
if (!Array.isArray(options.statuses)) return {
|
|
1249
|
+
data: null,
|
|
1250
|
+
error: createValidationError("Status filters must be an array.")
|
|
1251
|
+
};
|
|
1252
|
+
if (options.statuses.length > 6) return {
|
|
1253
|
+
data: null,
|
|
1254
|
+
error: createValidationError("A maximum of 6 status filters can be provided.")
|
|
1255
|
+
};
|
|
1256
|
+
if (new Set(options.statuses).size !== options.statuses.length) return {
|
|
1257
|
+
data: null,
|
|
1258
|
+
error: createValidationError("Status filters must be unique.")
|
|
1259
|
+
};
|
|
1260
|
+
if (!options.statuses.every((status) => Webhooks.STATUS_VALUES.has(status))) {
|
|
1261
|
+
const validValues = quoteValues(Webhooks.STATUS_VALUES);
|
|
1262
|
+
return {
|
|
1263
|
+
data: null,
|
|
1264
|
+
error: createValidationError(`Invalid status filter provided. Valid values are: ${validValues}.`)
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1218
1268
|
const { dates, error: dateError } = parseDateInputs({
|
|
1219
1269
|
createdAfter: options?.createdAfter,
|
|
1220
1270
|
createdBefore: options?.createdBefore
|
|
@@ -1240,7 +1290,7 @@ var Webhooks = class Webhooks {
|
|
|
1240
1290
|
query: {
|
|
1241
1291
|
created_after: dates.createdAfter,
|
|
1242
1292
|
created_before: dates.createdBefore,
|
|
1243
|
-
statuses: options?.statuses,
|
|
1293
|
+
statuses: options?.statuses?.join(","),
|
|
1244
1294
|
webhook: options?.webhook,
|
|
1245
1295
|
limit: options?.limit,
|
|
1246
1296
|
offset: options?.offset
|
|
@@ -2030,8 +2080,16 @@ var Metrics = class {
|
|
|
2030
2080
|
};
|
|
2031
2081
|
}
|
|
2032
2082
|
};
|
|
2033
|
-
var Suppressions = class {
|
|
2083
|
+
var Suppressions = class Suppressions {
|
|
2034
2084
|
mailchannels;
|
|
2085
|
+
static SOURCE_VALUES = /* @__PURE__ */ new Set([
|
|
2086
|
+
"api",
|
|
2087
|
+
"unsubscribe_link",
|
|
2088
|
+
"list_unsubscribe",
|
|
2089
|
+
"hard_bounce",
|
|
2090
|
+
"spam_complaint"
|
|
2091
|
+
]);
|
|
2092
|
+
static DELETE_SOURCE_VALUES = /* @__PURE__ */ new Set([...Suppressions.SOURCE_VALUES, "all"]);
|
|
2035
2093
|
constructor(mailchannels) {
|
|
2036
2094
|
this.mailchannels = mailchannels;
|
|
2037
2095
|
}
|
|
@@ -2072,6 +2130,13 @@ var Suppressions = class {
|
|
|
2072
2130
|
}
|
|
2073
2131
|
async delete(recipient, source) {
|
|
2074
2132
|
let error = null;
|
|
2133
|
+
if (source !== void 0 && !Suppressions.DELETE_SOURCE_VALUES.has(source)) {
|
|
2134
|
+
error = createValidationError(`Source must be one of ${quoteValues(Suppressions.DELETE_SOURCE_VALUES)}.`);
|
|
2135
|
+
return {
|
|
2136
|
+
success: false,
|
|
2137
|
+
error
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2075
2140
|
await this.mailchannels.delete(`/tx/v1/suppression-list/recipients/${encodeURIComponent(recipient)}`, {
|
|
2076
2141
|
query: { source },
|
|
2077
2142
|
onResponseError: async ({ response }) => {
|
|
@@ -2094,6 +2159,13 @@ var Suppressions = class {
|
|
|
2094
2159
|
error
|
|
2095
2160
|
};
|
|
2096
2161
|
}
|
|
2162
|
+
if (options?.source !== void 0 && !Suppressions.SOURCE_VALUES.has(options.source)) {
|
|
2163
|
+
error = createValidationError(`Source must be one of ${quoteValues(Suppressions.SOURCE_VALUES)}.`);
|
|
2164
|
+
return {
|
|
2165
|
+
data: null,
|
|
2166
|
+
error
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2097
2169
|
const { dates, error: dateError } = parseDateInputs({
|
|
2098
2170
|
createdBefore: options?.createdBefore,
|
|
2099
2171
|
createdAfter: options?.createdAfter
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EmailsQueueResponse, EmailsSendOptions, EmailsSendResponse, MailChannelsClientOptions } from "../../_chunks/mailchannels.mjs";
|
|
2
|
-
import { Transport
|
|
2
|
+
import { Transport, TransportOptions, Transporter } from "nodemailer";
|
|
3
3
|
import MimeNode from "nodemailer/lib/mime-node";
|
|
4
|
-
type MailChannelsTransportSendOptions = Pick<EmailsSendOptions, "campaignId" | "tracking" | "transactional" | "unsubscribe">;
|
|
5
|
-
type MailChannelsTransportSendMode = "sync" | "async";
|
|
6
|
-
interface MailChannelsTransportOptions<T extends MailChannelsTransportSendMode = "async"> extends MailChannelsClientOptions {
|
|
4
|
+
export type MailChannelsTransportSendOptions = Pick<EmailsSendOptions, "campaignId" | "tracking" | "transactional" | "unsubscribe">;
|
|
5
|
+
export type MailChannelsTransportSendMode = "sync" | "async";
|
|
6
|
+
export interface MailChannelsTransportOptions<T extends MailChannelsTransportSendMode = "async"> extends MailChannelsClientOptions {
|
|
7
7
|
/**
|
|
8
8
|
* The MailChannels Email API key.
|
|
9
9
|
*/
|
|
@@ -14,7 +14,7 @@ interface MailChannelsTransportOptions<T extends MailChannelsTransportSendMode =
|
|
|
14
14
|
*/
|
|
15
15
|
sendMode?: T;
|
|
16
16
|
}
|
|
17
|
-
interface MailChannelsTransportInfo<T extends MailChannelsTransportSendMode> {
|
|
17
|
+
export interface MailChannelsTransportInfo<T extends MailChannelsTransportSendMode> {
|
|
18
18
|
messageId: string | null;
|
|
19
19
|
accepted: string[];
|
|
20
20
|
rejected: string[];
|
|
@@ -22,12 +22,14 @@ interface MailChannelsTransportInfo<T extends MailChannelsTransportSendMode> {
|
|
|
22
22
|
response: (T extends "sync" ? EmailsSendResponse : EmailsQueueResponse) | null;
|
|
23
23
|
}
|
|
24
24
|
declare module "nodemailer" {
|
|
25
|
-
function createTransport<T>(transport: Transport<T> | TransportOptions, defaults?: TransportOptions): Transporter<T
|
|
25
|
+
function createTransport<T>(transport: Transport<T> | TransportOptions, defaults?: TransportOptions): Transporter<T>;
|
|
26
|
+
interface SendMailOptions {
|
|
27
|
+
mailchannels?: MailChannelsTransportSendOptions;
|
|
28
|
+
}
|
|
26
29
|
}
|
|
27
30
|
declare module "nodemailer/lib/mailer" {
|
|
28
31
|
interface Options {
|
|
29
32
|
mailchannels?: MailChannelsTransportSendOptions;
|
|
30
33
|
}
|
|
31
34
|
}
|
|
32
|
-
declare const mailchannelsTransport: <T extends MailChannelsTransportSendMode = "async">(options: MailChannelsTransportOptions<T>) => Transport
|
|
33
|
-
export { MailChannelsTransportInfo, MailChannelsTransportOptions, MailChannelsTransportSendMode, MailChannelsTransportSendOptions, mailchannelsTransport };
|
|
35
|
+
export declare const mailchannelsTransport: <T extends MailChannelsTransportSendMode = "async">(options: MailChannelsTransportOptions<T>) => Transport<MailChannelsTransportInfo<T>>;
|
|
@@ -5,9 +5,10 @@ const parseAddress = (address) => {
|
|
|
5
5
|
if (!address) return "";
|
|
6
6
|
if (Array.isArray(address)) return parseAddress(address[0]);
|
|
7
7
|
if (typeof address === "string") return address;
|
|
8
|
+
if (!address.address) return "";
|
|
8
9
|
return {
|
|
9
10
|
email: address.address,
|
|
10
|
-
name: address.name
|
|
11
|
+
name: address.name
|
|
11
12
|
};
|
|
12
13
|
};
|
|
13
14
|
const parseAddresses = (addresses) => {
|
|
@@ -41,7 +42,7 @@ const parseDkim = (dkim) => {
|
|
|
41
42
|
if ("keys" in dkim) throw new Error("Multiple DKIM signatures are not supported");
|
|
42
43
|
let privateKey;
|
|
43
44
|
if (typeof dkim.privateKey === "string") privateKey = dkim.privateKey;
|
|
44
|
-
else if (dkim.privateKey
|
|
45
|
+
else if (dkim.privateKey && "key" in dkim.privateKey && "passphrase" in dkim.privateKey) try {
|
|
45
46
|
privateKey = createPrivateKey({
|
|
46
47
|
key: dkim.privateKey.key,
|
|
47
48
|
passphrase: dkim.privateKey.passphrase
|
|
@@ -62,7 +63,8 @@ const parseDkim = (dkim) => {
|
|
|
62
63
|
const parseHeaders = (headers) => {
|
|
63
64
|
if (!headers) return;
|
|
64
65
|
if (Array.isArray(headers)) return headers.reduce((acc, { key, value }) => {
|
|
65
|
-
|
|
66
|
+
if (value == void 0) return acc;
|
|
67
|
+
acc[key] = value.toString();
|
|
66
68
|
return acc;
|
|
67
69
|
}, {});
|
|
68
70
|
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, Array.isArray(value) ? value.join(",") : value && typeof value === "object" && "value" in value ? String(value.value) : String(value)]));
|
|
@@ -94,7 +96,10 @@ const mailchannelsTransport = (options) => {
|
|
|
94
96
|
messageId: null,
|
|
95
97
|
accepted: [],
|
|
96
98
|
rejected: [],
|
|
97
|
-
envelope: mail.message
|
|
99
|
+
envelope: mail.message?.getEnvelope() ?? {
|
|
100
|
+
from: false,
|
|
101
|
+
to: []
|
|
102
|
+
},
|
|
98
103
|
response: null
|
|
99
104
|
};
|
|
100
105
|
mail.normalize(async (err, data) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const createSimulator: (options?: {
|
|
1
|
+
export declare const createSimulator: (options?: {
|
|
2
2
|
host?: string;
|
|
3
3
|
port?: number;
|
|
4
4
|
silent?: boolean;
|
|
@@ -16,5 +16,4 @@ declare const createSimulator: (options?: {
|
|
|
16
16
|
host?: string;
|
|
17
17
|
port?: number;
|
|
18
18
|
}): Promise<string>;
|
|
19
|
-
};
|
|
20
|
-
export { createSimulator };
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailchannels-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Node.js SDK to integrate MailChannels Email API into your JavaScript or TypeScript server-side applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,19 +52,18 @@
|
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
54
54
|
"@types/markdown-it": "^14.2.0",
|
|
55
|
-
"@types/node": "^26.
|
|
56
|
-
"@
|
|
57
|
-
"@vitest/coverage-v8": "^4.1.11",
|
|
55
|
+
"@types/node": "^26.5.0",
|
|
56
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
58
57
|
"changelogen": "^0.6.2",
|
|
59
|
-
"nodemailer": "^
|
|
60
|
-
"obuild": "^0.4.
|
|
61
|
-
"oxlint": "^1.
|
|
58
|
+
"nodemailer": "^10.0.1",
|
|
59
|
+
"obuild": "^0.4.39",
|
|
60
|
+
"oxlint": "^1.82.0",
|
|
62
61
|
"scule": "^1.3.0",
|
|
63
62
|
"typescript": "^6.0.3",
|
|
64
|
-
"vitepress": "^2.0.0-alpha.
|
|
63
|
+
"vitepress": "^2.0.0-alpha.20",
|
|
65
64
|
"vitepress-plugin-group-icons": "^1.7.6",
|
|
66
65
|
"vitepress-plugin-llms": "^1.13.5",
|
|
67
|
-
"vitest": "^
|
|
66
|
+
"vitest": "^5.0.0"
|
|
68
67
|
},
|
|
69
68
|
"engines": {
|
|
70
69
|
"node": ">=20"
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
"scripts": {
|
|
73
72
|
"build": "obuild",
|
|
74
73
|
"parity:fixtures": "node scripts/generate-parity-fixtures.ts",
|
|
75
|
-
"release": "pnpm lint && pnpm test && pnpm build && changelogen --bump",
|
|
74
|
+
"release": "pnpm lint && pnpm test && pnpm build && changelogen --bump && node scripts/update-examples-sdk-version.ts",
|
|
76
75
|
"cli": "pnpx jiti src/cli/index.ts",
|
|
77
76
|
"simulate": "pnpx jiti src/cli/index.ts simulate",
|
|
78
77
|
"lint": "oxlint",
|