mailchannels-sdk 0.3.6

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.
@@ -0,0 +1,1358 @@
1
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
2
+ ErrorCode2[ErrorCode2["BadRequest"] = 400] = "BadRequest";
3
+ ErrorCode2[ErrorCode2["Unauthorized"] = 401] = "Unauthorized";
4
+ ErrorCode2[ErrorCode2["Forbidden"] = 403] = "Forbidden";
5
+ ErrorCode2[ErrorCode2["NotFound"] = 404] = "NotFound";
6
+ ErrorCode2[ErrorCode2["Conflict"] = 409] = "Conflict";
7
+ ErrorCode2[ErrorCode2["PayloadTooLarge"] = 413] = "PayloadTooLarge";
8
+ ErrorCode2[ErrorCode2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
9
+ return ErrorCode2;
10
+ })(ErrorCode || {});
11
+ const getStatusError = (response, errors = {}) => {
12
+ return errors[response.status] || response._data?.message || "Unknown error.";
13
+ };
14
+
15
+ const parseRecipientString = (input) => {
16
+ const trimmed = input.trim();
17
+ const match = trimmed.match(/^([^<]*)<([^@\s]+@[^>\s]+)>$/);
18
+ if (match) {
19
+ const [, name, email] = match;
20
+ return { email: email?.trim() || "", name: name?.trim() };
21
+ }
22
+ return { email: trimmed };
23
+ };
24
+ const parseRecipient = (recipient) => {
25
+ if (typeof recipient === "string") {
26
+ return parseRecipientString(recipient);
27
+ }
28
+ if (recipient?.email) {
29
+ return { email: recipient.email, name: recipient.name };
30
+ }
31
+ };
32
+ const parseArrayRecipients = (recipients) => {
33
+ if (!recipients) return;
34
+ if (typeof recipients === "string") {
35
+ return [parseRecipientString(recipients)];
36
+ }
37
+ if (Array.isArray(recipients)) {
38
+ return recipients.map((recipient) => parseRecipient(recipient)).filter((recipient) => Boolean(recipient));
39
+ }
40
+ return [recipients];
41
+ };
42
+
43
+ const stripPemHeaders = (pem) => pem.replace(/-----[^-]+-----|\s|#.*$/gm, "");
44
+
45
+ class Emails {
46
+ constructor(mailchannels) {
47
+ this.mailchannels = mailchannels;
48
+ }
49
+ /**
50
+ * Send an email using MailChannels Email API.
51
+ * @param options - The email options to send.
52
+ * @param dryRun - When set to `true`, the message will not be sent. Instead, the fully rendered message will be returned in the `data` property of the response. The default value is `false`.
53
+ * @example
54
+ * ```ts
55
+ * const mailchannels = new MailChannels('your-api-key')
56
+ * const { success } = await mailchannels.emails.send({
57
+ * to: 'to@example.com',
58
+ * from: 'from@example.com',
59
+ * subject: 'Test',
60
+ * html: 'Test'
61
+ * })
62
+ * ```
63
+ */
64
+ async send(options, dryRun = false) {
65
+ const { cc, bcc, from, to, html, text, mustaches, dkim } = options;
66
+ const data = { success: false, error: null };
67
+ const parsedFrom = parseRecipient(from);
68
+ if (!parsedFrom || !parsedFrom.email) {
69
+ data.error = "No sender provided. Use the `from` option to specify a sender";
70
+ return data;
71
+ }
72
+ const parsedTo = parseArrayRecipients(to);
73
+ if (!parsedTo || !parsedTo.length) {
74
+ data.error = "No recipients provided. Use the `to` option to specify at least one recipient";
75
+ return data;
76
+ }
77
+ if (!text && !html) {
78
+ data.error = "No email content provided";
79
+ return data;
80
+ }
81
+ const content = [];
82
+ const template_type = mustaches ? "mustache" : void 0;
83
+ if (text) content.push({ type: "text/plain", value: text, template_type });
84
+ if (html) content.push({ type: "text/html", value: html, template_type });
85
+ const payload = {
86
+ attachments: options.attachments,
87
+ personalizations: [{
88
+ bcc: parseArrayRecipients(bcc),
89
+ cc: parseArrayRecipients(cc),
90
+ to: parsedTo,
91
+ dkim_domain: dkim?.domain || void 0,
92
+ dkim_private_key: dkim?.privateKey ? stripPemHeaders(dkim.privateKey) : void 0,
93
+ dkim_selector: dkim?.selector || void 0,
94
+ dynamic_template_data: options.mustaches
95
+ }],
96
+ reply_to: parseRecipient(options.replyTo),
97
+ from: parsedFrom,
98
+ subject: options.subject,
99
+ content,
100
+ tracking_settings: options.tracking ? {
101
+ click_tracking: options.tracking.click ? { enable: options.tracking.click } : void 0,
102
+ open_tracking: options.tracking.open ? { enable: options.tracking.open } : void 0
103
+ } : void 0
104
+ };
105
+ const response = await this.mailchannels.post("/tx/v1/send", {
106
+ query: { "dry-run": dryRun },
107
+ body: payload,
108
+ onResponse: async ({ response: response2 }) => {
109
+ if (response2.ok) {
110
+ data.success = true;
111
+ return;
112
+ }
113
+ data.error = getStatusError(response2, {
114
+ [ErrorCode.BadRequest]: "Bad Request.",
115
+ [ErrorCode.Forbidden]: "User does not have access to this feature.",
116
+ [ErrorCode.PayloadTooLarge]: "The total message size should not exceed 20MB. This includes the message itself, headers, and the combined size of any attachments."
117
+ });
118
+ }
119
+ }).catch(() => null);
120
+ data.data = response?.data;
121
+ return data;
122
+ }
123
+ /**
124
+ * Validates a domain's email authentication setup by retrieving its DKIM, SPF, and Domain Lockdown status. This endpoint checks whether the domain is properly configured for secure email delivery.
125
+ * @param options - The domain options to check.
126
+ * @example
127
+ * ```ts
128
+ * const mailchannels = new MailChannels('your-api-key')
129
+ * const { results } = await mailchannels.emails.checkDomain({
130
+ * dkim: [{
131
+ * domain: 'example.com',
132
+ * privateKey: 'your-private-key',
133
+ * selector: 'mailchannels'
134
+ * }],
135
+ * domain: 'example.com',
136
+ * senderId: 'sender-id'
137
+ * })
138
+ * ```
139
+ */
140
+ async checkDomain(options) {
141
+ const { dkim, domain, senderId } = options;
142
+ const dkimOptions = Array.isArray(dkim) ? dkim : [dkim];
143
+ const data = { results: null, error: null };
144
+ const payload = {
145
+ dkim_settings: dkimOptions.map(({ domain: domain2, privateKey, selector }) => ({
146
+ dkim_domain: domain2,
147
+ dkim_private_key: stripPemHeaders(privateKey),
148
+ dkim_selector: selector
149
+ })),
150
+ domain,
151
+ sender_id: senderId
152
+ };
153
+ const response = await this.mailchannels.post("/tx/v1/check-domain", {
154
+ body: payload,
155
+ onResponseError: async ({ response: response2 }) => {
156
+ data.error = getStatusError(response2, {
157
+ [ErrorCode.BadRequest]: "Bad Request.",
158
+ [ErrorCode.Forbidden]: "User does not have access to this feature."
159
+ });
160
+ }
161
+ }).catch(() => null);
162
+ if (!response) return data;
163
+ data.results = {
164
+ dkim: response.check_results.dkim.map(({ dkim_domain, dkim_selector, reason, verdict }) => ({
165
+ domain: dkim_domain,
166
+ selector: dkim_selector,
167
+ reason,
168
+ verdict
169
+ })),
170
+ domainLockdown: response.check_results.domain_lockdown,
171
+ spf: response.check_results.spf,
172
+ references: response.references
173
+ };
174
+ return data;
175
+ }
176
+ }
177
+
178
+ class Webhooks {
179
+ constructor(mailchannels) {
180
+ this.mailchannels = mailchannels;
181
+ }
182
+ /**
183
+ * Enrolls the customer to receive event notifications via webhooks.
184
+ * @param endpoint - The URL to receive event notifications.
185
+ * @example
186
+ * ```ts
187
+ * const mailchannels = new MailChannels('your-api-key')
188
+ * const { success } = mailchannels.webhooks.enroll('https://example.com/api/webhooks/mailchannels')
189
+ * ```
190
+ */
191
+ async enroll(endpoint) {
192
+ const data = { success: false, error: null };
193
+ if (!endpoint) {
194
+ data.error = "No endpoint provided.";
195
+ return data;
196
+ }
197
+ await this.mailchannels.post("/tx/v1/webhook", {
198
+ query: {
199
+ endpoint
200
+ },
201
+ ignoreResponseError: true,
202
+ onResponse: async ({ response }) => {
203
+ if (response.ok) {
204
+ data.success = true;
205
+ return;
206
+ }
207
+ data.error = getStatusError(response, {
208
+ [ErrorCode.Conflict]: `Endpoint '${endpoint}' is already enrolled to receive notifications.`
209
+ });
210
+ }
211
+ });
212
+ return data;
213
+ }
214
+ /**
215
+ * Retrieves all registered webhook endpoints associated with the customer.
216
+ * @example
217
+ * ```ts
218
+ * const mailchannels = new MailChannels('your-api-key')
219
+ * const { webhooks } = await mailchannels.webhooks.list()
220
+ * ```
221
+ */
222
+ async list() {
223
+ const data = { webhooks: [], error: null };
224
+ const response = await this.mailchannels.get("/tx/v1/webhook", {
225
+ onResponseError: async ({ response: response2 }) => {
226
+ data.error = getStatusError(response2);
227
+ }
228
+ }).catch(() => []);
229
+ data.webhooks = response.map(({ webhook }) => webhook);
230
+ return data;
231
+ }
232
+ /**
233
+ * Deletes all registered webhook endpoints for the customer.
234
+ * @example
235
+ * ```ts
236
+ * const mailchannels = new MailChannels('your-api-key')
237
+ * const { success } = await mailchannels.webhooks.delete()
238
+ * ```
239
+ */
240
+ async delete() {
241
+ const data = { success: false, error: null };
242
+ await this.mailchannels.delete("/tx/v1/webhook", {
243
+ ignoreResponseError: true,
244
+ onResponse: async ({ response }) => {
245
+ if (!response.ok) {
246
+ data.error = getStatusError(response);
247
+ return;
248
+ }
249
+ data.success = true;
250
+ }
251
+ });
252
+ return data;
253
+ }
254
+ /**
255
+ * Retrieves the public key used to verify signatures on incoming webhook payloads.
256
+ * @param id - The ID of the key.
257
+ * @example
258
+ * ```ts
259
+ * const mailchannels = new MailChannels('your-api-key')
260
+ * const { key } = await mailchannels.webhooks.getSigningKey('key-id')
261
+ * ```
262
+ */
263
+ async getSigningKey(id) {
264
+ const data = { key: null, error: null };
265
+ const response = await this.mailchannels.get("/tx/v1/webhook/public-key", {
266
+ query: {
267
+ id
268
+ },
269
+ onResponseError: ({ response: response2 }) => {
270
+ data.error = getStatusError(response2, {
271
+ [ErrorCode.BadRequest]: "Bad Request.",
272
+ [ErrorCode.NotFound]: `The key '${id}' is not found.`
273
+ });
274
+ }
275
+ }).catch(() => null);
276
+ data.key = response?.key || null;
277
+ return data;
278
+ }
279
+ }
280
+
281
+ class SubAccounts {
282
+ constructor(mailchannels) {
283
+ this.mailchannels = mailchannels;
284
+ }
285
+ static HANDLE_PATTERN = /^[a-z0-9]{3,128}$/;
286
+ /**
287
+ * Creates a new sub-account under the parent account. Each sub-account must have a unique handle composed solely of lowercase alphanumeric characters. If no handle is provided, a random handle will be generated.
288
+ * @param handle - The handle of the sub-account to create. Sub-account handle must match the pattern `[a-z0-9]{3,128}`.
289
+ * @example
290
+ * ```ts
291
+ * const mailchannels = new MailChannels('your-api-key')
292
+ * const { account } = await mailchannels.subAccounts.create('validhandle123')
293
+ * ```
294
+ */
295
+ async create(handle) {
296
+ const data = { account: null, error: null };
297
+ if (handle) {
298
+ const isValidHandle = SubAccounts.HANDLE_PATTERN.test(handle);
299
+ if (!isValidHandle) {
300
+ data.error = "Invalid handle. Sub-account handle must match the pattern [a-z0-9]{3,128}";
301
+ return data;
302
+ }
303
+ }
304
+ const response = await this.mailchannels.post("/tx/v1/sub-account", {
305
+ body: handle ? { handle } : void 0,
306
+ onResponseError: ({ response: response2 }) => {
307
+ data.error = getStatusError(response2, {
308
+ [ErrorCode.Forbidden]: "The parent account does not have permission to create sub-accounts.",
309
+ [ErrorCode.Conflict]: `Sub-account with handle '${handle}' already exists.`
310
+ });
311
+ }
312
+ }).catch(() => null);
313
+ data.account = response;
314
+ return data;
315
+ }
316
+ /**
317
+ * Retrieves all sub-accounts associated with the parent account. The response is paginated with a default limit of 1000 sub-accounts per page and an offset of 0.
318
+ * @param options - The options to filter the list of sub-accounts.
319
+ * @example
320
+ * ```ts
321
+ * const mailchannels = new MailChannels('your-api-key')
322
+ * const { accounts } = await mailchannels.subAccounts.list()
323
+ * ```
324
+ */
325
+ async list(options) {
326
+ const data = { accounts: [], error: null };
327
+ if (typeof options?.limit === "number" && (options.limit < 1 || options.limit > 1e3)) {
328
+ data.error = "The limit value is invalid. Possible limit values are 1 to 1000.";
329
+ return data;
330
+ }
331
+ if (typeof options?.offset === "number" && options.offset < 0) {
332
+ data.error = "Offset must be greater than or equal to 0.";
333
+ return data;
334
+ }
335
+ const response = await this.mailchannels.get("/tx/v1/sub-account", {
336
+ query: options,
337
+ onResponseError: async ({ response: response2 }) => {
338
+ data.error = getStatusError(response2);
339
+ }
340
+ }).catch(() => []);
341
+ data.accounts = response;
342
+ return data;
343
+ }
344
+ /**
345
+ * Deletes the sub-account identified by its handle.
346
+ * @param handle - Handle of sub-account to be deleted.
347
+ * ```ts
348
+ * const mailchannels = new MailChannels('your-api-key')
349
+ * const { success } = await mailchannels.subAccounts.delete('validhandle123')
350
+ * ```
351
+ */
352
+ async delete(handle) {
353
+ const data = { success: false, error: null };
354
+ if (!handle) {
355
+ data.error = "No handle provided.";
356
+ return data;
357
+ }
358
+ await this.mailchannels.delete(`/tx/v1/sub-account/${handle}`, {
359
+ ignoreResponseError: true,
360
+ onResponse: async ({ response }) => {
361
+ if (!response.ok) {
362
+ data.error = getStatusError(response);
363
+ return;
364
+ }
365
+ data.success = true;
366
+ }
367
+ });
368
+ return data;
369
+ }
370
+ /**
371
+ * Suspends the sub-account identified by its handle. This action disables the account, preventing it from sending any emails until it is reactivated.
372
+ * @param handle - Handle of sub-account to be suspended.
373
+ * @example
374
+ * ```ts
375
+ * const mailchannels = new MailChannels('your-api-key')
376
+ * const { success } = await mailchannels.subAccounts.suspend('validhandle123')
377
+ * ```
378
+ */
379
+ async suspend(handle) {
380
+ const data = { success: false, error: null };
381
+ if (!handle) {
382
+ data.error = "No handle provided.";
383
+ return data;
384
+ }
385
+ await this.mailchannels.post(`/tx/v1/sub-account/${handle}/suspend`, {
386
+ ignoreResponseError: true,
387
+ onResponse: async ({ response }) => {
388
+ if (response.ok) {
389
+ data.success = true;
390
+ return;
391
+ }
392
+ data.error = getStatusError(response, {
393
+ [ErrorCode.NotFound]: `The specified sub-account '${handle}' does not exist.`
394
+ });
395
+ }
396
+ });
397
+ return data;
398
+ }
399
+ /**
400
+ * Activates a suspended sub-account identified by its handle, restoring its ability to send emails.
401
+ * @param handle - Handle of sub-account to be activated.
402
+ * @example
403
+ * ```ts
404
+ * const mailchannels = new MailChannels('your-api-key')
405
+ * const { success } = await mailchannels.subAccounts.activate('validhandle123')
406
+ * ```
407
+ */
408
+ async activate(handle) {
409
+ const data = { success: false, error: null };
410
+ if (!handle) {
411
+ data.error = "No handle provided.";
412
+ return data;
413
+ }
414
+ await this.mailchannels.post(`/tx/v1/sub-account/${handle}/activate`, {
415
+ ignoreResponseError: true,
416
+ onResponse: async ({ response }) => {
417
+ if (response.ok) {
418
+ data.success = true;
419
+ return;
420
+ }
421
+ data.error = getStatusError(response, {
422
+ [ErrorCode.Forbidden]: "The parent account does not have permission to activate the sub-account.",
423
+ [ErrorCode.NotFound]: `The specified sub-account '${handle}' does not exist.`
424
+ });
425
+ }
426
+ });
427
+ return data;
428
+ }
429
+ /**
430
+ * Creates a new API key for the specified sub-account.
431
+ * @param handle - Handle of the sub-account to create API key for.
432
+ * @example
433
+ * ```ts
434
+ * const mailchannels = new MailChannels('your-api-key')
435
+ * const { key } = await mailchannels.subAccounts.createApiKey('validhandle123')
436
+ * ```
437
+ */
438
+ async createApiKey(handle) {
439
+ const data = { key: null, error: null };
440
+ if (!handle) {
441
+ data.error = "No handle provided.";
442
+ return data;
443
+ }
444
+ const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/api-key`, {
445
+ onResponseError: async ({ response: response2 }) => {
446
+ data.error = getStatusError(response2, {
447
+ [ErrorCode.Forbidden]: "You can't create API keys for this sub-account.",
448
+ [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`,
449
+ [ErrorCode.UnprocessableEntity]: "You have reached the limit of API keys you can create for this sub-account."
450
+ });
451
+ }
452
+ }).catch(() => null);
453
+ if (!response) return data;
454
+ data.key = {
455
+ id: response.id,
456
+ value: response.key
457
+ };
458
+ return data;
459
+ }
460
+ /**
461
+ * Retrieves details of all API keys associated with the specified sub-account. For security reasons, the full API key is not returned; only the key ID and a partially redacted version are provided.
462
+ * @param handle - Handle of the sub-account to retrieve the API key for.
463
+ * @example
464
+ * ```ts
465
+ * const mailchannels = new MailChannels('your-api-key')
466
+ * const { keys } = await mailchannels.subAccounts.listApiKeys('validhandle123')
467
+ * ```
468
+ */
469
+ async listApiKeys(handle) {
470
+ const data = { keys: [], error: null };
471
+ if (!handle) {
472
+ data.error = "No handle provided.";
473
+ return data;
474
+ }
475
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/api-key`, {
476
+ onResponseError: async ({ response: response2 }) => {
477
+ data.error = getStatusError(response2, {
478
+ [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
479
+ });
480
+ }
481
+ }).catch(() => []);
482
+ data.keys = response.map((key) => ({
483
+ id: key.id,
484
+ value: key.key
485
+ }));
486
+ return data;
487
+ }
488
+ /**
489
+ * Deletes the API key identified by its ID for the specified sub-account.
490
+ * @param handle - Handle of the sub-account for which the API key should be deleted.
491
+ * @param id - The ID of the API key to delete.
492
+ * @example
493
+ * ```ts
494
+ * const mailchannels = new MailChannels('your-api-key')
495
+ * const { success } = await mailchannels.subAccounts.deleteApiKey('validhandle123', 1)
496
+ * ```
497
+ */
498
+ async deleteApiKey(handle, id) {
499
+ const data = { success: false, error: null };
500
+ if (!handle) {
501
+ data.error = "No handle provided.";
502
+ return data;
503
+ }
504
+ await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/api-key/${id}`, {
505
+ ignoreResponseError: true,
506
+ onResponse: async ({ response }) => {
507
+ if (response.ok) {
508
+ data.success = true;
509
+ return;
510
+ }
511
+ data.error = getStatusError(response, {
512
+ [ErrorCode.BadRequest]: "Missing or invalid API key ID."
513
+ });
514
+ }
515
+ });
516
+ return data;
517
+ }
518
+ /**
519
+ * Creates a new SMTP password for the specified sub-account.
520
+ * @param handle - Handle of the sub-account to create SMTP password for.
521
+ * @example
522
+ * ```ts
523
+ * const mailchannels = new MailChannels('your-api-key')
524
+ * const { password } = await mailchannels.subAccounts.createSmtpPassword('validhandle123')
525
+ * ```
526
+ */
527
+ async createSmtpPassword(handle) {
528
+ const data = { password: null, error: null };
529
+ if (!handle) {
530
+ data.error = "No handle provided.";
531
+ return data;
532
+ }
533
+ const response = await this.mailchannels.post(`/tx/v1/sub-account/${handle}/smtp-password`, {
534
+ onResponseError: async ({ response: response2 }) => {
535
+ data.error = getStatusError(response2, {
536
+ [ErrorCode.Forbidden]: "You can't create SMTP passwords for this sub-account.",
537
+ [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`,
538
+ [ErrorCode.UnprocessableEntity]: "You have reached the limit of SMTP passwords you can create for this sub-account."
539
+ });
540
+ }
541
+ }).catch(() => null);
542
+ if (!response) return data;
543
+ data.password = {
544
+ enabled: response.enabled,
545
+ id: response.id,
546
+ value: response.smtp_password
547
+ };
548
+ return data;
549
+ }
550
+ /**
551
+ * Retrieves details of all SMTP passwords associated with the specified sub-account. For security, the full SMTP password is not returned; only the password ID and a partially redacted version are provided.
552
+ * @param handle - Handle of the sub-account to retrieve the SMTP password for.
553
+ * @example
554
+ * ```ts
555
+ * const mailchannels = new MailChannels('your-api-key')
556
+ * const { passwords } = await mailchannels.subAccounts.listSmtpPasswords('validhandle123')
557
+ * ```
558
+ */
559
+ async listSmtpPasswords(handle) {
560
+ const data = { passwords: [], error: null };
561
+ if (!handle) {
562
+ data.error = "No handle provided.";
563
+ return data;
564
+ }
565
+ const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/smtp-password`, {
566
+ onResponseError: async ({ response: response2 }) => {
567
+ data.error = getStatusError(response2, {
568
+ [ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
569
+ });
570
+ }
571
+ }).catch(() => []);
572
+ data.passwords = response.map((password) => ({
573
+ enabled: password.enabled,
574
+ id: password.id,
575
+ value: password.smtp_password
576
+ }));
577
+ return data;
578
+ }
579
+ /**
580
+ * Deletes the SMTP password identified by its ID for the specified sub-account.
581
+ * @param handle - Handle of the sub-account for which the SMTP password should be deleted.
582
+ * @param id - The ID of the SMTP password to delete.
583
+ * @example
584
+ * ```ts
585
+ * const mailchannels = new MailChannels('your-api-key')
586
+ * const { success } = await mailchannels.subAccounts.deleteSmtpPassword('validhandle123', 1)
587
+ * ```
588
+ */
589
+ async deleteSmtpPassword(handle, id) {
590
+ const data = { success: false, error: null };
591
+ if (!handle) {
592
+ data.error = "No handle provided.";
593
+ return data;
594
+ }
595
+ await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/smtp-password/${id}`, {
596
+ ignoreResponseError: true,
597
+ onResponse: async ({ response }) => {
598
+ if (response.ok) {
599
+ data.success = true;
600
+ return;
601
+ }
602
+ data.error = getStatusError(response, {
603
+ [ErrorCode.BadRequest]: "Missing or invalid SMTP password ID."
604
+ });
605
+ }
606
+ });
607
+ return data;
608
+ }
609
+ }
610
+
611
+ class Service {
612
+ constructor(mailchannels) {
613
+ this.mailchannels = mailchannels;
614
+ }
615
+ /**
616
+ * Retrieve the condition of the service
617
+ * @example
618
+ * ```ts
619
+ * const mailchannels = new MailChannels('your-api-key')
620
+ * const { success } = await mailchannels.service.status()
621
+ * ```
622
+ */
623
+ async status() {
624
+ const data = { success: false, error: null };
625
+ await this.mailchannels.get("/inbound/v1/status", {
626
+ ignoreResponseError: true,
627
+ onResponse: async ({ response }) => {
628
+ if (response.ok) {
629
+ data.success = true;
630
+ return;
631
+ }
632
+ data.error = getStatusError(response);
633
+ }
634
+ });
635
+ return data;
636
+ }
637
+ /**
638
+ * Get a list of your subscriptions to MailChannels Inbound
639
+ * @example
640
+ * ```ts
641
+ * const mailchannels = new MailChannels('your-api-key')
642
+ * const { subscriptions } = await mailchannels.service.subscriptions()
643
+ * ```
644
+ */
645
+ async subscriptions() {
646
+ const data = { subscriptions: [], error: null };
647
+ const response = await this.mailchannels.get("/inbound/v1/subscriptions", {
648
+ onResponseError: async ({ response: response2 }) => {
649
+ data.error = getStatusError(response2, {
650
+ [ErrorCode.NotFound]: "We could not find a customer that matched the customerHandle."
651
+ });
652
+ }
653
+ }).catch(() => []);
654
+ data.subscriptions = response;
655
+ return data;
656
+ }
657
+ /**
658
+ * Submit a false negative or false positive report.
659
+ * @param options - The report options
660
+ */
661
+ async report(options) {
662
+ const data = { success: false, error: null };
663
+ const { type, ...payload } = options;
664
+ await this.mailchannels.post("/inbound/v1/report", {
665
+ query: {
666
+ report_type: type
667
+ },
668
+ body: payload,
669
+ onResponse: async ({ response }) => {
670
+ if (response.ok) {
671
+ data.success = true;
672
+ return;
673
+ }
674
+ data.error = getStatusError(response);
675
+ }
676
+ });
677
+ return data;
678
+ }
679
+ }
680
+
681
+ class Domains {
682
+ constructor(mailchannels) {
683
+ this.mailchannels = mailchannels;
684
+ }
685
+ /**
686
+ * Provision a single domain to use MailChannels Inbound.
687
+ * @param options - The domain data to provision.
688
+ * @example
689
+ * ```ts
690
+ * const mailchannels = new MailChannels('your-api-key')
691
+ * const { data } = await mailchannels.domains.provision({
692
+ * domain: 'example.com',
693
+ * subscriptionHandle: 'your-subscription-handle'
694
+ * })
695
+ * ```
696
+ */
697
+ async provision(options) {
698
+ const { associateKey, overwrite, ...payload } = options;
699
+ const data = { data: null, error: null };
700
+ const response = await this.mailchannels.post("/inbound/v1/domains", {
701
+ query: {
702
+ "associate-key": associateKey,
703
+ "overwrite": overwrite
704
+ },
705
+ body: payload,
706
+ onResponseError: async ({ response: response2 }) => {
707
+ data.error = getStatusError(response2, {
708
+ [ErrorCode.BadRequest]: "Bad Request, returned in the case that an error occurs while converting an A-label domain to a U-label domain name.",
709
+ [ErrorCode.Forbidden]: "The limit on associated domains is reached or you are attempting to associate a domain with a subscription that is not your own.",
710
+ [ErrorCode.Conflict]: `The domain '${options.domain}' is already provisioned, and is associated with a different customer.`
711
+ });
712
+ }
713
+ }).catch(() => null);
714
+ data.data = response;
715
+ return data;
716
+ }
717
+ /**
718
+ * Provision up to 1000 domains to use MailChannels Inbound.
719
+ * @param options - The options to provision the domains.
720
+ * @param domains - The list of domains to provision.
721
+ * @example
722
+ * ```ts
723
+ * const mailchannels = new MailChannels('your-api-key')
724
+ * const { results } = await mailchannels.domains.bulkProvision({
725
+ * subscriptionHandle: 'your-subscription-handle'
726
+ * }, [
727
+ * {
728
+ * domain: 'example.com',
729
+ * admins: ['support@example.com']
730
+ * },
731
+ * {
732
+ * domain: 'example2.com'
733
+ * }
734
+ * ])
735
+ * ```
736
+ */
737
+ async bulkProvision(options, domains) {
738
+ const { associateKey, overwrite, subscriptionHandle } = options;
739
+ const data = { results: null, error: null };
740
+ if (!domains || !domains.length) {
741
+ data.error = "No domains provided.";
742
+ return data;
743
+ }
744
+ if (domains.length > 1e3) {
745
+ data.error = "The maximum number of domains to be provisioned is 1000.";
746
+ return data;
747
+ }
748
+ const response = await this.mailchannels.post("/inbound/v1/domains/batch", {
749
+ query: {
750
+ subscriptionHandle,
751
+ "associate-key": associateKey,
752
+ "overwrite": overwrite
753
+ },
754
+ body: { domains },
755
+ onResponseError: async ({ response: response2 }) => {
756
+ data.error = getStatusError(response2, {
757
+ [ErrorCode.BadRequest]: "Bad Request, returned in the case that a domain name fails RFC 5891 validation.",
758
+ [ErrorCode.Forbidden]: "The limit on associated domains is reached or you are attempting to associate a domain with a subscription that is not your own."
759
+ });
760
+ }
761
+ }).catch(() => null);
762
+ if (!response) return data;
763
+ data.results = response;
764
+ return data;
765
+ }
766
+ /**
767
+ * Fetch a list of all domains associated with this API key.
768
+ * @param options - The options to filter the list of domains.
769
+ * @example
770
+ * ```ts
771
+ * const mailchannels = new MailChannels('your-api-key')
772
+ * const { domains } = await mailchannels.domains.list()
773
+ * ```
774
+ */
775
+ async list(options) {
776
+ const data = { domains: [], total: 0, error: null };
777
+ if (typeof options?.limit === "number" && (options.limit < 1 || options.limit > 5e3)) {
778
+ data.error = "The limit value is invalid. Possible limit values are 1 to 5000.";
779
+ return data;
780
+ }
781
+ if (typeof options?.offset === "number" && options.offset < 0) {
782
+ data.error = "Offset must be greater than or equal to 0.";
783
+ return data;
784
+ }
785
+ const response = await this.mailchannels.get("/inbound/v1/domains", {
786
+ query: options,
787
+ onResponseError: async ({ response: response2 }) => {
788
+ data.error = getStatusError(response2);
789
+ }
790
+ }).catch(() => null);
791
+ if (!response) return data;
792
+ data.domains = response.domains;
793
+ data.total = response.total;
794
+ return data;
795
+ }
796
+ /**
797
+ * De-provision a domain to cease protecting it with MailChannels Inbound.
798
+ * @param domain - The domain name to be removed.
799
+ * @example
800
+ * ```ts
801
+ * const mailchannels = new MailChannels('your-api-key')
802
+ * const { success } = await mailchannels.domains.delete('example.com')
803
+ * ```
804
+ */
805
+ async delete(domain) {
806
+ const data = { success: false, error: null };
807
+ if (!domain) {
808
+ data.error = "No domain provided.";
809
+ return data;
810
+ }
811
+ await this.mailchannels.delete(`/inbound/v1/domains/${domain}`, {
812
+ ignoreResponseError: true,
813
+ onResponse: async ({ response }) => {
814
+ if (response.ok) {
815
+ data.success = true;
816
+ return;
817
+ }
818
+ data.error = getStatusError(response, {
819
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, or the domain in the request is an alias domain.",
820
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
821
+ });
822
+ }
823
+ });
824
+ return data;
825
+ }
826
+ /**
827
+ * Add an entry to a domain blocklist or safelist.
828
+ * @param domain - The domain name.
829
+ * @param options - The options to add a list entry.
830
+ * @example
831
+ * ```ts
832
+ * const mailchannels = new MailChannels('your-api-key')
833
+ * const { entry } = await mailchannels.domains.addListEntry('example.com', {
834
+ * listName: 'safelist',
835
+ * item: 'name@domain.com'
836
+ * })
837
+ * ```
838
+ */
839
+ async addListEntry(domain, options) {
840
+ const { listName, item } = options;
841
+ const data = { entry: null, error: null };
842
+ if (!domain) {
843
+ data.error = "No domain provided.";
844
+ return data;
845
+ }
846
+ if (!listName) {
847
+ data.error = "No list name provided.";
848
+ return data;
849
+ }
850
+ const response = await this.mailchannels.post(`/inbound/v1/domains/${domain}/lists/${listName}`, {
851
+ body: { item },
852
+ onResponseError: async ({ response: response2 }) => {
853
+ data.error = getStatusError(response2, {
854
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
855
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
856
+ });
857
+ }
858
+ }).catch(() => null);
859
+ if (!response) return data;
860
+ data.entry = {
861
+ action: response.action,
862
+ item: response.item,
863
+ type: response.item_type
864
+ };
865
+ return data;
866
+ }
867
+ /**
868
+ * Get domain list entries.
869
+ * @param domain - The domain name.
870
+ * @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
871
+ * @example
872
+ * ```ts
873
+ * const mailchannels = new MailChannels('your-api-key')
874
+ * const { entries } = await mailchannels.domains.listEntries('example.com', 'safelist')
875
+ * ```
876
+ */
877
+ async listEntries(domain, listName) {
878
+ const data = { entries: [], error: null };
879
+ if (!domain) {
880
+ data.error = "No domain provided.";
881
+ return data;
882
+ }
883
+ if (!listName) {
884
+ data.error = "No list name provided.";
885
+ return data;
886
+ }
887
+ const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/lists/${listName}`, {
888
+ onResponseError: async ({ response: response2 }) => {
889
+ data.error = getStatusError(response2, {
890
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
891
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
892
+ });
893
+ }
894
+ }).catch(() => null);
895
+ if (!response) return data;
896
+ data.entries = response.map(({ action, item, item_type }) => ({
897
+ action,
898
+ item,
899
+ type: item_type
900
+ }));
901
+ return data;
902
+ }
903
+ /**
904
+ * Delete item from domain list.
905
+ * @param email - The domain name whose list will be modified.
906
+ * @param options - The options for the list entry to delete.
907
+ * @example
908
+ * ```ts
909
+ * const mailchannels = new MailChannels('your-api-key')
910
+ * const { success } = await mailchannels.domains.deleteListEntry('example.com', {
911
+ * listName: 'safelist',
912
+ * item: 'name@domain.com'
913
+ * })
914
+ * ```
915
+ */
916
+ async deleteListEntry(domain, options) {
917
+ const { listName, item } = options;
918
+ const data = { success: false, error: null };
919
+ if (!domain) {
920
+ data.error = "No domain provided.";
921
+ return data;
922
+ }
923
+ if (!listName) {
924
+ data.error = "No list name provided.";
925
+ return data;
926
+ }
927
+ await this.mailchannels.delete(`/inbound/v1/domains/${domain}/lists/${listName}`, {
928
+ query: { item },
929
+ ignoreResponseError: true,
930
+ onResponse: async ({ response }) => {
931
+ if (response.ok) {
932
+ data.success = true;
933
+ return;
934
+ }
935
+ data.error = getStatusError(response, {
936
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
937
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
938
+ });
939
+ }
940
+ });
941
+ return data;
942
+ }
943
+ /**
944
+ * Generate a link that allows a user to log in as a domain administrator.
945
+ * @param domain - The domain name.
946
+ * @example
947
+ * ```ts
948
+ * const mailchannels = new MailChannels('your-api-key')
949
+ * const { link } = await mailchannels.domains.createLoginLink('example.com')
950
+ * ```
951
+ */
952
+ async createLoginLink(domain) {
953
+ const data = { link: null, error: null };
954
+ if (!domain) {
955
+ data.error = "No domain provided.";
956
+ return data;
957
+ }
958
+ const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/login-link`, {
959
+ onResponseError: async ({ response: response2 }) => {
960
+ data.error = getStatusError(response2, {
961
+ [ErrorCode.Unauthorized]: "The domain does not belong to this customer.",
962
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
963
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
964
+ });
965
+ }
966
+ }).catch(() => null);
967
+ if (!response) return data;
968
+ data.link = response.loginLink;
969
+ return data;
970
+ }
971
+ /**
972
+ * Sets the list of downstream addreses for the domain. This action deletes any existing downstream address for the domain before creating new ones. If the `records` parameter is an empty array, all downstream address records will be deleted.
973
+ * @param domain - The domain name.
974
+ * @param records - The list of records to set for the domain. A maximum of 10 records can be set.
975
+ * @example
976
+ * ```ts
977
+ * const mailchannels = new MailChannels('your-api-key')
978
+ * const { success } = await mailchannels.domains.setDownstreamAddress('example.com', [
979
+ * {
980
+ * port: 25,
981
+ * priority: 10,
982
+ * target: 'example.com.',
983
+ * weight: 10
984
+ * }
985
+ * ])
986
+ * ```
987
+ */
988
+ async setDownstreamAddress(domain, records = []) {
989
+ const data = { success: false, error: null };
990
+ if (!domain) {
991
+ data.error = "No domain provided.";
992
+ return data;
993
+ }
994
+ if (records.length > 10) {
995
+ data.error = "The maximum of records to be set is 10.";
996
+ return data;
997
+ }
998
+ await this.mailchannels.put(`/inbound/v1/domains/${domain}/downstream-address`, {
999
+ body: { records },
1000
+ ignoreResponseError: true,
1001
+ onResponse: async ({ response }) => {
1002
+ if (response.ok) {
1003
+ data.success = true;
1004
+ return;
1005
+ }
1006
+ data.error = getStatusError(response, {
1007
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1008
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1009
+ });
1010
+ }
1011
+ });
1012
+ return data;
1013
+ }
1014
+ /**
1015
+ * Retrieve stored downstream addresses for the domain.
1016
+ * @param domain - The domain name.
1017
+ * @param options - The options to filter the list of downstream addresses.
1018
+ * @example
1019
+ * ```ts
1020
+ * const mailchannels = new MailChannels('your-api-key')
1021
+ * const { records } = await mailchannels.domains.listDownstreamAddresses('example.com')
1022
+ * ```
1023
+ */
1024
+ async listDownstreamAddresses(domain, options) {
1025
+ const data = { records: [], error: null };
1026
+ if (!domain) {
1027
+ data.error = "No domain provided.";
1028
+ return data;
1029
+ }
1030
+ if (typeof options?.limit === "number" && options.limit < 1) {
1031
+ data.error = "The limit value is invalid. Only positive values are allowed.";
1032
+ return data;
1033
+ }
1034
+ if (typeof options?.offset === "number" && options.offset < 0) {
1035
+ data.error = "Offset must be greater than or equal to 0.";
1036
+ return data;
1037
+ }
1038
+ const response = await this.mailchannels.get(`/inbound/v1/domains/${domain}/downstream-address`, {
1039
+ query: options,
1040
+ onResponseError: async ({ response: response2 }) => {
1041
+ data.error = getStatusError(response2, {
1042
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1043
+ [ErrorCode.NotFound]: `The domain '${domain}' was not found.`
1044
+ });
1045
+ }
1046
+ }).catch(() => null);
1047
+ if (!response) return data;
1048
+ data.records = response.records;
1049
+ return data;
1050
+ }
1051
+ /**
1052
+ * Update the API key that is associated with a domain.
1053
+ * @param domain - The domain name.
1054
+ * @param key - The new API key to associate with this domain.
1055
+ * @example
1056
+ * ```ts
1057
+ * const mailchannels = new MailChannels('your-api-key')
1058
+ * const { success } = await mailchannels.domains.updateApiKey('example.com', 'your-api-key')
1059
+ * ```
1060
+ */
1061
+ async updateApiKey(domain, key) {
1062
+ const data = { success: false, error: null };
1063
+ if (!domain) {
1064
+ data.error = "No domain provided.";
1065
+ return data;
1066
+ }
1067
+ if (!key) {
1068
+ data.error = "No API key provided.";
1069
+ return data;
1070
+ }
1071
+ await this.mailchannels.put(`/inbound/v1/domains/${domain}/api-key`, {
1072
+ body: { apiKey: key },
1073
+ ignoreResponseError: true,
1074
+ onResponse: async ({ response }) => {
1075
+ if (response.ok) {
1076
+ data.success = true;
1077
+ return;
1078
+ }
1079
+ data.error = getStatusError(response, {
1080
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1081
+ [ErrorCode.NotFound]: "The domain does not exist."
1082
+ });
1083
+ }
1084
+ });
1085
+ return data;
1086
+ }
1087
+ }
1088
+
1089
+ class Users {
1090
+ constructor(mailchannels) {
1091
+ this.mailchannels = mailchannels;
1092
+ }
1093
+ /**
1094
+ * Create a recipient user.
1095
+ * @param email - The email address of the user to create.
1096
+ * @param options - The options for the user to create.
1097
+ * @example
1098
+ * ```ts
1099
+ * const mailchannels = new MailChannels('your-api-key')
1100
+ * const { user } = await mailchannels.users.create("name@example.com", {
1101
+ * admin: true
1102
+ * })
1103
+ * ```
1104
+ */
1105
+ async create(email, options) {
1106
+ const { admin, filter, listEntries } = options || {};
1107
+ const data = { user: null, error: null };
1108
+ if (!email) {
1109
+ data.error = "No email address provided.";
1110
+ return data;
1111
+ }
1112
+ const response = await this.mailchannels.put("/inbound/v1/users", {
1113
+ query: {
1114
+ email_address: email,
1115
+ admin: Boolean(admin),
1116
+ filter
1117
+ },
1118
+ body: {
1119
+ list_entries: listEntries
1120
+ },
1121
+ onResponseError: async ({ response: response2 }) => {
1122
+ data.error = getStatusError(response2, {
1123
+ [ErrorCode.BadRequest]: `The email address '${email}' is invalid.`
1124
+ });
1125
+ }
1126
+ }).catch(() => null);
1127
+ if (!response) return data;
1128
+ data.user = {
1129
+ email: response.recipient.email_address,
1130
+ roles: response.recipient.roles,
1131
+ filter: response.recipient.filter,
1132
+ listEntries: response.list_entries.map(({ item, item_type, action }) => ({
1133
+ item,
1134
+ type: item_type,
1135
+ action
1136
+ }))
1137
+ };
1138
+ return data;
1139
+ }
1140
+ /**
1141
+ * Add item to recipient user list
1142
+ * @param email - The email address of the recipient whose list will be modified.
1143
+ * @param options - The options for the list entry to add.
1144
+ * @example
1145
+ * ```ts
1146
+ * const mailchannels = new MailChannels('your-api-key')
1147
+ * const { entry } = await mailchannels.users.addListEntry('name@example.com', {
1148
+ * listName: 'safelist',
1149
+ * item: 'name@domain.com'
1150
+ * })
1151
+ * ```
1152
+ */
1153
+ async addListEntry(email, options) {
1154
+ const { listName, item } = options;
1155
+ const data = { entry: null, error: null };
1156
+ if (!email) {
1157
+ data.error = "No email provided.";
1158
+ return data;
1159
+ }
1160
+ if (!listName) {
1161
+ data.error = "No list name provided.";
1162
+ return data;
1163
+ }
1164
+ const response = await this.mailchannels.post(`/inbound/v1/users/${email}/lists/${listName}`, {
1165
+ body: { item },
1166
+ onResponseError: async ({ response: response2 }) => {
1167
+ data.error = getStatusError(response2, {
1168
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1169
+ [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
1170
+ });
1171
+ }
1172
+ }).catch(() => null);
1173
+ if (!response) return data;
1174
+ data.entry = {
1175
+ action: response.action,
1176
+ item: response.item,
1177
+ type: response.item_type
1178
+ };
1179
+ return data;
1180
+ }
1181
+ /**
1182
+ * Get recipient list entries.
1183
+ * @param email - The email address of the recipient whose list will be fetched.
1184
+ * @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
1185
+ * @example
1186
+ * ```ts
1187
+ * const mailchannels = new MailChannels('your-api-key')
1188
+ * const { entries } = await mailchannels.users.listEntries('name@example.com', 'safelist')
1189
+ * ```
1190
+ */
1191
+ async listEntries(email, listName) {
1192
+ const data = { entries: [], error: null };
1193
+ if (!email) {
1194
+ data.error = "No email provided.";
1195
+ return data;
1196
+ }
1197
+ if (!listName) {
1198
+ data.error = "No list name provided.";
1199
+ return data;
1200
+ }
1201
+ const response = await this.mailchannels.get(`/inbound/v1/users/${email}/lists/${listName}`, {
1202
+ onResponseError: async ({ response: response2 }) => {
1203
+ data.error = getStatusError(response2, {
1204
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1205
+ [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
1206
+ });
1207
+ }
1208
+ }).catch(() => null);
1209
+ if (!response) return data;
1210
+ data.entries = response.map(({ action, item, item_type }) => ({
1211
+ action,
1212
+ item,
1213
+ type: item_type
1214
+ }));
1215
+ return data;
1216
+ }
1217
+ /**
1218
+ * Delete item from recipient list.
1219
+ * @param email - The email address of the recipient whose list will be modified.
1220
+ * @param options - The options for the list entry to delete.
1221
+ * @example
1222
+ * ```ts
1223
+ * const mailchannels = new MailChannels('your-api-key')
1224
+ * const { success } = await mailchannels.users.deleteListEntry('name@example.com', {
1225
+ * listName: 'safelist',
1226
+ * item: 'name@domain.com'
1227
+ * })
1228
+ * ```
1229
+ */
1230
+ async deleteListEntry(email, options) {
1231
+ const { listName, item } = options;
1232
+ const data = { success: false, error: null };
1233
+ if (!email) {
1234
+ data.error = "No email provided.";
1235
+ return data;
1236
+ }
1237
+ if (!listName) {
1238
+ data.error = "No list name provided.";
1239
+ return data;
1240
+ }
1241
+ await this.mailchannels.delete(`/inbound/v1/users/${email}/lists/${listName}`, {
1242
+ query: { item },
1243
+ ignoreResponseError: true,
1244
+ onResponse: async ({ response }) => {
1245
+ if (response.ok) {
1246
+ data.success = true;
1247
+ return;
1248
+ }
1249
+ data.error = getStatusError(response, {
1250
+ [ErrorCode.Forbidden]: "The domain is associated with an api key that is different than the one in the request, the domain is associated with a different customer, or the domain in the request is an alias domain.",
1251
+ [ErrorCode.NotFound]: `The recipient '${email}' was not found.`
1252
+ });
1253
+ }
1254
+ });
1255
+ return data;
1256
+ }
1257
+ }
1258
+
1259
+ class Lists {
1260
+ constructor(mailchannels) {
1261
+ this.mailchannels = mailchannels;
1262
+ }
1263
+ /**
1264
+ * Add item to account-level list
1265
+ * @param options - The options for the list entry to add.
1266
+ * @example
1267
+ * ```ts
1268
+ * const mailchannels = new MailChannels('your-api-key')
1269
+ * const { entry } = await mailchannels.lists.addListEntry({
1270
+ * listName: 'safelist',
1271
+ * item: 'name@domain.com'
1272
+ * })
1273
+ * ```
1274
+ */
1275
+ async addListEntry(options) {
1276
+ const { listName, item } = options;
1277
+ const data = { entry: null, error: null };
1278
+ if (!listName) {
1279
+ data.error = "No list name provided.";
1280
+ return data;
1281
+ }
1282
+ const response = await this.mailchannels.post(`/inbound/v1/lists/${listName}`, {
1283
+ body: { item },
1284
+ onResponseError: async ({ response: response2 }) => {
1285
+ data.error = getStatusError(response2);
1286
+ }
1287
+ }).catch(() => null);
1288
+ if (!response) return data;
1289
+ data.entry = {
1290
+ action: response.action,
1291
+ item: response.item,
1292
+ type: response.item_type
1293
+ };
1294
+ return data;
1295
+ }
1296
+ /**
1297
+ * Get account-level list entries.
1298
+ * @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
1299
+ * @example
1300
+ * ```ts
1301
+ * const mailchannels = new MailChannels('your-api-key')
1302
+ * const { entries } = await mailchannels.lists.listEntries('safelist')
1303
+ * ```
1304
+ */
1305
+ async listEntries(listName) {
1306
+ const data = { entries: [], error: null };
1307
+ if (!listName) {
1308
+ data.error = "No list name provided.";
1309
+ return data;
1310
+ }
1311
+ const response = await this.mailchannels.get(`/inbound/v1/lists/${listName}`, {
1312
+ onResponseError: async ({ response: response2 }) => {
1313
+ data.error = getStatusError(response2);
1314
+ }
1315
+ }).catch(() => null);
1316
+ if (!response) return data;
1317
+ data.entries = response.map(({ action, item, item_type }) => ({
1318
+ action,
1319
+ item,
1320
+ type: item_type
1321
+ }));
1322
+ return data;
1323
+ }
1324
+ /**
1325
+ * Delete item from account-level list.
1326
+ * @param options - The options for the list entry to delete.
1327
+ * @example
1328
+ * ```ts
1329
+ * const mailchannels = new MailChannels('your-api-key')
1330
+ * const { success } = await mailchannels.lists.deleteListEntry({
1331
+ * listName: 'safelist',
1332
+ * item: 'name@domain.com'
1333
+ * })
1334
+ * ```
1335
+ */
1336
+ async deleteListEntry(options) {
1337
+ const { listName, item } = options;
1338
+ const data = { success: false, error: null };
1339
+ if (!listName) {
1340
+ data.error = "No list name provided.";
1341
+ return data;
1342
+ }
1343
+ await this.mailchannels.delete(`/inbound/v1/lists/${listName}`, {
1344
+ query: { item },
1345
+ ignoreResponseError: true,
1346
+ onResponse: async ({ response }) => {
1347
+ if (response.ok) {
1348
+ data.success = true;
1349
+ return;
1350
+ }
1351
+ data.error = getStatusError(response);
1352
+ }
1353
+ });
1354
+ return data;
1355
+ }
1356
+ }
1357
+
1358
+ export { Domains, Emails, Lists, Service, SubAccounts, Users, Webhooks };