mailchannels-sdk 0.3.7 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +177 -159
- package/dist/mailchannels.d.mts +6 -4
- package/dist/mailchannels.d.ts +6 -4
- package/dist/mailchannels.mjs +7 -3
- package/dist/modules.d.mts +1 -1
- package/dist/modules.d.ts +1 -1
- package/dist/modules.mjs +626 -96
- package/dist/shared/{mailchannels-sdk.BDB65ygx.d.mts → mailchannels-sdk.Bakg_aFG.d.mts} +1179 -668
- package/dist/shared/{mailchannels-sdk.BDB65ygx.d.ts → mailchannels-sdk.Bakg_aFG.d.ts} +1179 -668
- package/package.json +25 -27
package/dist/modules.mjs
CHANGED
|
@@ -9,7 +9,16 @@ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
|
|
|
9
9
|
return ErrorCode2;
|
|
10
10
|
})(ErrorCode || {});
|
|
11
11
|
const getStatusError = (response, errors = {}) => {
|
|
12
|
-
|
|
12
|
+
const statusText = errors[response.status] || "Unknown error.";
|
|
13
|
+
let details = "";
|
|
14
|
+
if (typeof response._data === "string") {
|
|
15
|
+
details = response._data;
|
|
16
|
+
} else if (response._data?.message) {
|
|
17
|
+
details = response._data.message;
|
|
18
|
+
} else if (Array.isArray(response._data?.errors) && response._data.errors.length) {
|
|
19
|
+
details = response._data.errors.join(", ");
|
|
20
|
+
}
|
|
21
|
+
return details ? `${statusText} ${details}` : statusText;
|
|
13
22
|
};
|
|
14
23
|
|
|
15
24
|
const parseRecipientString = (input) => {
|
|
@@ -84,6 +93,7 @@ class Emails {
|
|
|
84
93
|
if (html) content.push({ type: "text/html", value: html, template_type });
|
|
85
94
|
const payload = {
|
|
86
95
|
attachments: options.attachments,
|
|
96
|
+
campaign_id: options.campaignId,
|
|
87
97
|
personalizations: [{
|
|
88
98
|
bcc: parseArrayRecipients(bcc),
|
|
89
99
|
cc: parseArrayRecipients(cc),
|
|
@@ -100,7 +110,8 @@ class Emails {
|
|
|
100
110
|
tracking_settings: options.tracking ? {
|
|
101
111
|
click_tracking: options.tracking.click ? { enable: options.tracking.click } : void 0,
|
|
102
112
|
open_tracking: options.tracking.open ? { enable: options.tracking.open } : void 0
|
|
103
|
-
} : void 0
|
|
113
|
+
} : void 0,
|
|
114
|
+
transactional: options.transactional
|
|
104
115
|
};
|
|
105
116
|
const response = await this.mailchannels.post("/tx/v1/send", {
|
|
106
117
|
query: { "dry-run": dryRun },
|
|
@@ -181,7 +192,7 @@ class Webhooks {
|
|
|
181
192
|
}
|
|
182
193
|
/**
|
|
183
194
|
* Enrolls the customer to receive event notifications via webhooks.
|
|
184
|
-
* @param endpoint - The URL to receive event notifications.
|
|
195
|
+
* @param endpoint - The URL to receive event notifications. Must be no longer than `8000` characters.
|
|
185
196
|
* @example
|
|
186
197
|
* ```ts
|
|
187
198
|
* const mailchannels = new MailChannels('your-api-key')
|
|
@@ -194,6 +205,10 @@ class Webhooks {
|
|
|
194
205
|
data.error = "No endpoint provided.";
|
|
195
206
|
return data;
|
|
196
207
|
}
|
|
208
|
+
if (endpoint.length > 8e3) {
|
|
209
|
+
data.error = "The endpoint exceeds the maximum length of 8000 characters.";
|
|
210
|
+
return data;
|
|
211
|
+
}
|
|
197
212
|
await this.mailchannels.post("/tx/v1/webhook", {
|
|
198
213
|
query: {
|
|
199
214
|
endpoint
|
|
@@ -276,33 +291,75 @@ class Webhooks {
|
|
|
276
291
|
data.key = response?.key || null;
|
|
277
292
|
return data;
|
|
278
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Validates whether your enrolled webhook(s) respond with an HTTP `2xx` status code. Sends a test request to each webhook containing your customer handle, a hardcoded event type (`test`), a hardcoded sender email (`test@mailchannels.com`), a timestamp, a request ID (provided or generated), and an SMTP ID. The response includes the HTTP status code and body returned by each webhook.
|
|
296
|
+
* @param requestId - Optional identifier in the webhook payload. If not provided, a value will be automatically generated. Must not exceed 28 characters.
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
300
|
+
* const { allPassed, results } = await mailchannels.webhooks.validate('optional-request-id')
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
async validate(requestId) {
|
|
304
|
+
const data = { allPassed: false, results: [], error: null };
|
|
305
|
+
if (requestId && requestId.length > 28) {
|
|
306
|
+
data.error = "The request id should not exceed 28 characters.";
|
|
307
|
+
return data;
|
|
308
|
+
}
|
|
309
|
+
const response = await this.mailchannels.post("/tx/v1/webhook/validate", {
|
|
310
|
+
body: {
|
|
311
|
+
request_id: requestId
|
|
312
|
+
},
|
|
313
|
+
onResponseError: ({ response: response2 }) => {
|
|
314
|
+
data.error = getStatusError(response2, {
|
|
315
|
+
[ErrorCode.BadRequest]: "Bad Request.",
|
|
316
|
+
[ErrorCode.NotFound]: "No webhooks found for the account."
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}).catch(() => null);
|
|
320
|
+
if (response) {
|
|
321
|
+
data.allPassed = response.all_passed;
|
|
322
|
+
data.results = response.results;
|
|
323
|
+
}
|
|
324
|
+
return data;
|
|
325
|
+
}
|
|
279
326
|
}
|
|
280
327
|
|
|
281
328
|
class SubAccounts {
|
|
282
329
|
constructor(mailchannels) {
|
|
283
330
|
this.mailchannels = mailchannels;
|
|
284
331
|
}
|
|
332
|
+
static COMPANY_PATTERN = /^.{3,128}$/;
|
|
285
333
|
static HANDLE_PATTERN = /^[a-z0-9]{3,128}$/;
|
|
286
334
|
/**
|
|
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
|
|
335
|
+
* 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. Note that Sub-accounts are only available to parent accounts on 100K and higher plans.
|
|
336
|
+
* @param companyName - The name of the company associated with the sub-account. This name is used for display purposes only and does not affect the functionality of the sub-account. The length must be between 3 and 128 characters.
|
|
337
|
+
* @param handle - A unique name for the sub-account to be created. The length must be between 3 and 128 characters, and it may contain only lowercase letters and numbers. If not provided, a random handle will be generated.
|
|
289
338
|
* @example
|
|
290
339
|
* ```ts
|
|
291
340
|
* const mailchannels = new MailChannels('your-api-key')
|
|
292
|
-
* const { account } = await mailchannels.subAccounts.create('validhandle123')
|
|
341
|
+
* const { account } = await mailchannels.subAccounts.create('My Company', 'validhandle123')
|
|
293
342
|
* ```
|
|
294
343
|
*/
|
|
295
|
-
async create(handle) {
|
|
344
|
+
async create(companyName, handle) {
|
|
296
345
|
const data = { account: null, error: null };
|
|
346
|
+
const isValidCompany = SubAccounts.COMPANY_PATTERN.test(companyName);
|
|
347
|
+
if (!isValidCompany) {
|
|
348
|
+
data.error = "Invalid company name. Company name must be between 3 and 128 characters.";
|
|
349
|
+
return data;
|
|
350
|
+
}
|
|
297
351
|
if (handle) {
|
|
298
352
|
const isValidHandle = SubAccounts.HANDLE_PATTERN.test(handle);
|
|
299
353
|
if (!isValidHandle) {
|
|
300
|
-
data.error = "Invalid handle. Sub-account handle must
|
|
354
|
+
data.error = "Invalid handle. Sub-account handle must be between 3 and 128 characters and contain only lowercase letters and numbers.";
|
|
301
355
|
return data;
|
|
302
356
|
}
|
|
303
357
|
}
|
|
304
358
|
const response = await this.mailchannels.post("/tx/v1/sub-account", {
|
|
305
|
-
body:
|
|
359
|
+
body: {
|
|
360
|
+
company_name: companyName,
|
|
361
|
+
handle
|
|
362
|
+
},
|
|
306
363
|
onResponseError: ({ response: response2 }) => {
|
|
307
364
|
data.error = getStatusError(response2, {
|
|
308
365
|
[ErrorCode.Forbidden]: "The parent account does not have permission to create sub-accounts.",
|
|
@@ -310,7 +367,12 @@ class SubAccounts {
|
|
|
310
367
|
});
|
|
311
368
|
}
|
|
312
369
|
}).catch(() => null);
|
|
313
|
-
|
|
370
|
+
if (!response) return data;
|
|
371
|
+
data.account = {
|
|
372
|
+
companyName: response.company_name,
|
|
373
|
+
enabled: response.enabled,
|
|
374
|
+
handle: response.handle
|
|
375
|
+
};
|
|
314
376
|
return data;
|
|
315
377
|
}
|
|
316
378
|
/**
|
|
@@ -338,7 +400,11 @@ class SubAccounts {
|
|
|
338
400
|
data.error = getStatusError(response2);
|
|
339
401
|
}
|
|
340
402
|
}).catch(() => []);
|
|
341
|
-
data.accounts = response
|
|
403
|
+
data.accounts = response.map((account) => ({
|
|
404
|
+
companyName: account.company_name,
|
|
405
|
+
enabled: account.enabled,
|
|
406
|
+
handle: account.handle
|
|
407
|
+
}));
|
|
342
408
|
return data;
|
|
343
409
|
}
|
|
344
410
|
/**
|
|
@@ -606,76 +672,430 @@ class SubAccounts {
|
|
|
606
672
|
});
|
|
607
673
|
return data;
|
|
608
674
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
675
|
+
/**
|
|
676
|
+
* Retrieves the limit of a specified sub-account. A value of `-1` indicates that the sub-account inherits the parent account's limit, allowing the sub-account to utilize any remaining capacity within the parent account's allocation.
|
|
677
|
+
* @param handle - Handle of the sub-account to retrieve the limit for.
|
|
678
|
+
* @example
|
|
679
|
+
* ```ts
|
|
680
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
681
|
+
* const { limit } = await mailchannels.subAccounts.getLimit('validhandle123')
|
|
682
|
+
* ```
|
|
683
|
+
*/
|
|
684
|
+
async getLimit(handle) {
|
|
685
|
+
const data = { limit: null, error: null };
|
|
686
|
+
if (!handle) {
|
|
687
|
+
data.error = "No handle provided.";
|
|
688
|
+
return data;
|
|
689
|
+
}
|
|
690
|
+
const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/limit`, {
|
|
691
|
+
onResponseError: async ({ response: response2 }) => {
|
|
692
|
+
data.error = getStatusError(response2, {
|
|
693
|
+
[ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}).catch(() => null);
|
|
697
|
+
if (!response) return data;
|
|
698
|
+
data.limit = response;
|
|
699
|
+
return data;
|
|
614
700
|
}
|
|
615
701
|
/**
|
|
616
|
-
*
|
|
702
|
+
* Sets the limit for the specified sub-account.
|
|
703
|
+
* @param handle - Handle of the sub-account to set limit for.
|
|
704
|
+
* @param limit - The limits to set for the sub-account. The minimum allowed sends is `0`
|
|
617
705
|
* @example
|
|
618
706
|
* ```ts
|
|
619
707
|
* const mailchannels = new MailChannels('your-api-key')
|
|
620
|
-
* const { success } = await mailchannels.
|
|
708
|
+
* const { success } = await mailchannels.subAccounts.setLimit('validhandle123', { sends: 1000 })
|
|
621
709
|
* ```
|
|
622
710
|
*/
|
|
623
|
-
async
|
|
711
|
+
async setLimit(handle, limit) {
|
|
624
712
|
const data = { success: false, error: null };
|
|
625
|
-
|
|
713
|
+
if (!handle) {
|
|
714
|
+
data.error = "No handle provided.";
|
|
715
|
+
return data;
|
|
716
|
+
}
|
|
717
|
+
await this.mailchannels.put(`/tx/v1/sub-account/${handle}/limit`, {
|
|
718
|
+
body: limit,
|
|
626
719
|
ignoreResponseError: true,
|
|
627
720
|
onResponse: async ({ response }) => {
|
|
628
721
|
if (response.ok) {
|
|
629
722
|
data.success = true;
|
|
630
723
|
return;
|
|
631
724
|
}
|
|
632
|
-
data.error = getStatusError(response
|
|
725
|
+
data.error = getStatusError(response, {
|
|
726
|
+
[ErrorCode.BadRequest]: "Bad Request.",
|
|
727
|
+
[ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
|
|
728
|
+
});
|
|
633
729
|
}
|
|
634
730
|
});
|
|
635
731
|
return data;
|
|
636
732
|
}
|
|
637
733
|
/**
|
|
638
|
-
*
|
|
734
|
+
* Deletes the limit for the specified sub-account. After a successful deletion, the specified sub-account will be limited to the parent account's limit.
|
|
735
|
+
* @param handle - Handle of the sub-account to delete limit for.
|
|
639
736
|
* @example
|
|
640
737
|
* ```ts
|
|
641
738
|
* const mailchannels = new MailChannels('your-api-key')
|
|
642
|
-
* const {
|
|
739
|
+
* const { success } = await mailchannels.subAccounts.deleteLimit('validhandle123')
|
|
643
740
|
* ```
|
|
644
741
|
*/
|
|
645
|
-
async
|
|
646
|
-
const data = {
|
|
647
|
-
|
|
742
|
+
async deleteLimit(handle) {
|
|
743
|
+
const data = { success: false, error: null };
|
|
744
|
+
if (!handle) {
|
|
745
|
+
data.error = "No handle provided.";
|
|
746
|
+
return data;
|
|
747
|
+
}
|
|
748
|
+
await this.mailchannels.delete(`/tx/v1/sub-account/${handle}/limit`, {
|
|
749
|
+
ignoreResponseError: true,
|
|
750
|
+
onResponse: async ({ response }) => {
|
|
751
|
+
if (response.ok) {
|
|
752
|
+
data.success = true;
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
data.error = getStatusError(response, {
|
|
756
|
+
[ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
});
|
|
760
|
+
return data;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Retrieves usage statistics for the specified sub-account during the current billing period.
|
|
764
|
+
* @param handle - Handle of the sub-account to query usage stats for.
|
|
765
|
+
* @example
|
|
766
|
+
* ```ts
|
|
767
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
768
|
+
* const { usage } = await mailchannels.subAccounts.getUsage('validhandle123')
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
async getUsage(handle) {
|
|
772
|
+
const data = { usage: null, error: null };
|
|
773
|
+
if (!handle) {
|
|
774
|
+
data.error = "No handle provided.";
|
|
775
|
+
return data;
|
|
776
|
+
}
|
|
777
|
+
const response = await this.mailchannels.get(`/tx/v1/sub-account/${handle}/usage`, {
|
|
648
778
|
onResponseError: async ({ response: response2 }) => {
|
|
649
779
|
data.error = getStatusError(response2, {
|
|
650
|
-
[ErrorCode.NotFound]:
|
|
780
|
+
[ErrorCode.NotFound]: `Sub-account with handle '${handle}' not found.`
|
|
651
781
|
});
|
|
652
782
|
}
|
|
653
|
-
}).catch(() =>
|
|
654
|
-
|
|
783
|
+
}).catch(() => null);
|
|
784
|
+
if (!response) return data;
|
|
785
|
+
data.usage = {
|
|
786
|
+
endDate: response.period_end_date,
|
|
787
|
+
startDate: response.period_start_date,
|
|
788
|
+
total: response.total_usage
|
|
789
|
+
};
|
|
655
790
|
return data;
|
|
656
791
|
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
const mapBuckets = (arr) => {
|
|
795
|
+
return arr.map(({ count, period_start }) => ({ count, periodStart: period_start }));
|
|
796
|
+
};
|
|
797
|
+
class Metrics {
|
|
798
|
+
constructor(mailchannels) {
|
|
799
|
+
this.mailchannels = mailchannels;
|
|
800
|
+
}
|
|
657
801
|
/**
|
|
658
|
-
*
|
|
659
|
-
* @param options -
|
|
802
|
+
* Retrieve engagement metrics for messages sent from your account, including counts of open and click events. Supports optional filters for time range, and campaign ID.
|
|
803
|
+
* @param options - Options to filter and customize the engagement metrics retrieval.
|
|
804
|
+
* @example
|
|
805
|
+
* ```ts
|
|
806
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
807
|
+
* const { engagement } = await mailchannels.metrics.engagement()
|
|
808
|
+
* ```
|
|
660
809
|
*/
|
|
661
|
-
async
|
|
662
|
-
const data = {
|
|
663
|
-
const
|
|
664
|
-
await this.mailchannels.post("/inbound/v1/report", {
|
|
810
|
+
async engagement(options) {
|
|
811
|
+
const data = { engagement: null, error: null };
|
|
812
|
+
const response = await this.mailchannels.get("/tx/v1/metrics/engagement", {
|
|
665
813
|
query: {
|
|
666
|
-
|
|
814
|
+
start_time: options?.startTime,
|
|
815
|
+
end_time: options?.endTime,
|
|
816
|
+
campaign_id: options?.campaignId,
|
|
817
|
+
interval: options?.interval
|
|
818
|
+
},
|
|
819
|
+
onResponseError: async ({ response: response2 }) => {
|
|
820
|
+
data.error = getStatusError(response2, {
|
|
821
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
}).catch(() => null);
|
|
825
|
+
if (!response) return data;
|
|
826
|
+
data.engagement = {
|
|
827
|
+
buckets: {
|
|
828
|
+
click: mapBuckets(response.buckets.click),
|
|
829
|
+
clickTrackingDelivered: mapBuckets(response.buckets.click_tracking_delivered),
|
|
830
|
+
open: mapBuckets(response.buckets.open),
|
|
831
|
+
openTrackingDelivered: mapBuckets(response.buckets.open_tracking_delivered)
|
|
832
|
+
},
|
|
833
|
+
click: response.click,
|
|
834
|
+
clickTrackingDelivered: response.click_tracking_delivered,
|
|
835
|
+
endTime: response.end_time,
|
|
836
|
+
open: response.open,
|
|
837
|
+
openTrackingDelivered: response.open_tracking_delivered,
|
|
838
|
+
startTime: response.start_time
|
|
839
|
+
};
|
|
840
|
+
return data;
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Retrieve performance metrics for messages sent from your account, including counts of processed, delivered, hard-bounced events. Supports optional filters for time range, and campaign ID.
|
|
844
|
+
* @param options - Options to filter and customize the performance metrics retrieval.
|
|
845
|
+
* @example
|
|
846
|
+
* ```ts
|
|
847
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
848
|
+
* const { performance } = await mailchannels.metrics.performance()
|
|
849
|
+
* ```
|
|
850
|
+
*/
|
|
851
|
+
async performance(options) {
|
|
852
|
+
const data = { performance: null, error: null };
|
|
853
|
+
const response = await this.mailchannels.get("/tx/v1/metrics/performance", {
|
|
854
|
+
query: {
|
|
855
|
+
start_time: options?.startTime,
|
|
856
|
+
end_time: options?.endTime,
|
|
857
|
+
campaign_id: options?.campaignId,
|
|
858
|
+
interval: options?.interval
|
|
859
|
+
},
|
|
860
|
+
onResponseError: async ({ response: response2 }) => {
|
|
861
|
+
data.error = getStatusError(response2, {
|
|
862
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
}).catch(() => null);
|
|
866
|
+
if (!response) return data;
|
|
867
|
+
data.performance = {
|
|
868
|
+
bounced: response.bounced,
|
|
869
|
+
buckets: {
|
|
870
|
+
bounced: mapBuckets(response.buckets.bounced),
|
|
871
|
+
delivered: mapBuckets(response.buckets.delivered),
|
|
872
|
+
processed: mapBuckets(response.buckets.processed)
|
|
873
|
+
},
|
|
874
|
+
delivered: response.delivered,
|
|
875
|
+
endTime: response.end_time,
|
|
876
|
+
processed: response.processed,
|
|
877
|
+
startTime: response.start_time
|
|
878
|
+
};
|
|
879
|
+
return data;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Retrieve recipient behaviour metrics for messages sent from your account, including counts of unsubscribed events. Supports optional filters for time range, and campaign ID.
|
|
883
|
+
* @param options - Options to filter and customize the recipient behaviour metrics retrieval.
|
|
884
|
+
* @example
|
|
885
|
+
* ```ts
|
|
886
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
887
|
+
* const { behaviour } = await mailchannels.metrics.recipientBehaviour()
|
|
888
|
+
* ```
|
|
889
|
+
*/
|
|
890
|
+
async recipientBehaviour(options) {
|
|
891
|
+
const data = { behaviour: null, error: null };
|
|
892
|
+
const response = await this.mailchannels.get("/tx/v1/metrics/recipient-behaviour", {
|
|
893
|
+
query: {
|
|
894
|
+
start_time: options?.startTime,
|
|
895
|
+
end_time: options?.endTime,
|
|
896
|
+
campaign_id: options?.campaignId,
|
|
897
|
+
interval: options?.interval
|
|
898
|
+
},
|
|
899
|
+
onResponseError: async ({ response: response2 }) => {
|
|
900
|
+
data.error = getStatusError(response2, {
|
|
901
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
}).catch(() => null);
|
|
905
|
+
if (!response) return data;
|
|
906
|
+
data.behaviour = {
|
|
907
|
+
buckets: {
|
|
908
|
+
unsubscribeDelivered: mapBuckets(response.buckets.unsubscribe_delivered),
|
|
909
|
+
unsubscribed: mapBuckets(response.buckets.unsubscribed)
|
|
910
|
+
},
|
|
911
|
+
endTime: response.end_time,
|
|
912
|
+
startTime: response.start_time,
|
|
913
|
+
unsubscribeDelivered: response.unsubscribe_delivered,
|
|
914
|
+
unsubscribed: response.unsubscribed
|
|
915
|
+
};
|
|
916
|
+
return data;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Retrieve volume metrics for messages sent from your account, including counts of processed, delivered and dropped events. Supports optional filters for time range and campaign ID.
|
|
920
|
+
* @param options - Options to filter and customize the volume metrics retrieval.
|
|
921
|
+
* @example
|
|
922
|
+
* ```ts
|
|
923
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
924
|
+
* const { volume } = await mailchannels.metrics.volume()
|
|
925
|
+
* ```
|
|
926
|
+
*/
|
|
927
|
+
async volume(options) {
|
|
928
|
+
const data = { volume: null, error: null };
|
|
929
|
+
const response = await this.mailchannels.get("/tx/v1/metrics/volume", {
|
|
930
|
+
query: {
|
|
931
|
+
start_time: options?.startTime,
|
|
932
|
+
end_time: options?.endTime,
|
|
933
|
+
campaign_id: options?.campaignId,
|
|
934
|
+
interval: options?.interval
|
|
935
|
+
},
|
|
936
|
+
onResponseError: async ({ response: response2 }) => {
|
|
937
|
+
data.error = getStatusError(response2, {
|
|
938
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
}).catch(() => null);
|
|
942
|
+
if (!response) return data;
|
|
943
|
+
data.volume = {
|
|
944
|
+
buckets: {
|
|
945
|
+
delivered: mapBuckets(response.buckets.delivered),
|
|
946
|
+
dropped: mapBuckets(response.buckets.dropped),
|
|
947
|
+
processed: mapBuckets(response.buckets.processed)
|
|
667
948
|
},
|
|
949
|
+
delivered: response.delivered,
|
|
950
|
+
dropped: response.dropped,
|
|
951
|
+
endTime: response.end_time,
|
|
952
|
+
processed: response.processed,
|
|
953
|
+
startTime: response.start_time
|
|
954
|
+
};
|
|
955
|
+
return data;
|
|
956
|
+
}
|
|
957
|
+
/**
|
|
958
|
+
* Retrieves usage statistics during the current billing period.
|
|
959
|
+
* @example
|
|
960
|
+
* ```ts
|
|
961
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
962
|
+
* const { usage } = await mailchannels.metrics.usage()
|
|
963
|
+
* ```
|
|
964
|
+
*/
|
|
965
|
+
async usage() {
|
|
966
|
+
const data = { usage: null, error: null };
|
|
967
|
+
const response = await this.mailchannels.get("/tx/v1/usage", {
|
|
968
|
+
onResponseError: async ({ response: response2 }) => {
|
|
969
|
+
data.error = getStatusError(response2);
|
|
970
|
+
}
|
|
971
|
+
}).catch(() => null);
|
|
972
|
+
if (!response) return data;
|
|
973
|
+
data.usage = {
|
|
974
|
+
endDate: response.period_end_date,
|
|
975
|
+
startDate: response.period_start_date,
|
|
976
|
+
total: response.total_usage
|
|
977
|
+
};
|
|
978
|
+
return data;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
class Suppressions {
|
|
983
|
+
constructor(mailchannels) {
|
|
984
|
+
this.mailchannels = mailchannels;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Creates suppression entries for the specified account. Parent accounts can create suppression entries for all associated sub-accounts. If `types` is not provided, it defaults to `non-transactional`. The operation is atomic, meaning all entries are successfully added or none are added if an error occurs.
|
|
988
|
+
* @param options - The details of the suppression entries to create.
|
|
989
|
+
* @example
|
|
990
|
+
* ```ts
|
|
991
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
992
|
+
* const { success } = await mailchannels.suppressions.create({
|
|
993
|
+
* // ...
|
|
994
|
+
* });
|
|
995
|
+
*/
|
|
996
|
+
async create(options) {
|
|
997
|
+
const data = { success: false, error: null };
|
|
998
|
+
const { addToSubAccounts, entries } = options;
|
|
999
|
+
const payload = {
|
|
1000
|
+
add_to_sub_accounts: addToSubAccounts,
|
|
1001
|
+
suppression_entries: entries.map((entry) => ({
|
|
1002
|
+
notes: entry.notes,
|
|
1003
|
+
recipient: entry.recipient,
|
|
1004
|
+
suppression_types: Array.from(new Set(entry.types))
|
|
1005
|
+
}))
|
|
1006
|
+
};
|
|
1007
|
+
await this.mailchannels.post("/tx/v1/suppression-list", {
|
|
668
1008
|
body: payload,
|
|
1009
|
+
ignoreResponseError: true,
|
|
669
1010
|
onResponse: async ({ response }) => {
|
|
670
1011
|
if (response.ok) {
|
|
671
1012
|
data.success = true;
|
|
672
1013
|
return;
|
|
673
1014
|
}
|
|
674
|
-
data.error = getStatusError(response
|
|
1015
|
+
data.error = getStatusError(response, {
|
|
1016
|
+
[ErrorCode.BadRequest]: "Bad Request.",
|
|
1017
|
+
[ErrorCode.Conflict]: "Conflict. One or more suppression entries in the request already exist and cannot be created again.",
|
|
1018
|
+
[ErrorCode.PayloadTooLarge]: "Payload too large. The request exceeds the maximum allowed total of 1000 suppression entries for the parent account and/or its sub-accounts."
|
|
1019
|
+
});
|
|
675
1020
|
}
|
|
676
1021
|
});
|
|
677
1022
|
return data;
|
|
678
1023
|
}
|
|
1024
|
+
/**
|
|
1025
|
+
* Deletes suppression entry associated with the account based on the specified recipient and source.
|
|
1026
|
+
* @param recipient - The email address of the suppression entry to delete.
|
|
1027
|
+
* @param source - The source of the suppression entry to be deleted. If source is not provided, it defaults to `api`. If source is set to `all`, all suppression entries related to the specified recipient will be deleted.
|
|
1028
|
+
* @example
|
|
1029
|
+
* ```ts
|
|
1030
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1031
|
+
* const { success } = await mailchannels.suppressions.delete('name@example.com', 'api');
|
|
1032
|
+
* ```
|
|
1033
|
+
*/
|
|
1034
|
+
async delete(recipient, source) {
|
|
1035
|
+
const data = { success: false, error: null };
|
|
1036
|
+
await this.mailchannels.delete(`/tx/v1/suppression-list/recipients/${recipient}`, {
|
|
1037
|
+
query: {
|
|
1038
|
+
source
|
|
1039
|
+
},
|
|
1040
|
+
ignoreResponseError: true,
|
|
1041
|
+
onResponse: async ({ response }) => {
|
|
1042
|
+
if (response.ok) {
|
|
1043
|
+
data.success = true;
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
data.error = getStatusError(response, {
|
|
1047
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
return data;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Retrieve suppression entries associated with the specified account. Supports filtering by recipient, source and creation date range. The response is paginated, with a default limit of `1000` entries per page and an offset of `0`.
|
|
1055
|
+
* @example
|
|
1056
|
+
* ```ts
|
|
1057
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1058
|
+
* const { list }= await mailchannels.suppressions.list();
|
|
1059
|
+
* ```
|
|
1060
|
+
* @param options - Options to filter and customize the suppression entries retrieval.
|
|
1061
|
+
*/
|
|
1062
|
+
async list(options) {
|
|
1063
|
+
const data = { list: [], error: null };
|
|
1064
|
+
if (typeof options?.limit === "number" && (options.limit < 1 || options.limit > 1e3)) {
|
|
1065
|
+
data.error = "The limit must be between 1 and 1000.";
|
|
1066
|
+
return data;
|
|
1067
|
+
}
|
|
1068
|
+
if (typeof options?.offset === "number" && options.offset < 0) {
|
|
1069
|
+
data.error = "Offset must be greater than or equal to 0.";
|
|
1070
|
+
return data;
|
|
1071
|
+
}
|
|
1072
|
+
const payload = {
|
|
1073
|
+
recipient: options?.recipient,
|
|
1074
|
+
source: options?.source,
|
|
1075
|
+
created_before: options?.createdBefore,
|
|
1076
|
+
created_after: options?.createdAfter,
|
|
1077
|
+
limit: options?.limit,
|
|
1078
|
+
offset: options?.offset
|
|
1079
|
+
};
|
|
1080
|
+
const response = await this.mailchannels.get("/tx/v1/suppression-list", {
|
|
1081
|
+
query: payload,
|
|
1082
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1083
|
+
data.error = getStatusError(response2, {
|
|
1084
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
}).catch(() => null);
|
|
1088
|
+
if (!response) return data;
|
|
1089
|
+
data.list = response.suppression_list.map((entry) => ({
|
|
1090
|
+
createdAt: entry.created_at,
|
|
1091
|
+
notes: entry.notes,
|
|
1092
|
+
recipient: entry.recipient,
|
|
1093
|
+
sender: entry.sender,
|
|
1094
|
+
source: entry.source,
|
|
1095
|
+
types: entry.suppression_types
|
|
1096
|
+
}));
|
|
1097
|
+
return data;
|
|
1098
|
+
}
|
|
679
1099
|
}
|
|
680
1100
|
|
|
681
1101
|
class Domains {
|
|
@@ -969,7 +1389,7 @@ class Domains {
|
|
|
969
1389
|
return data;
|
|
970
1390
|
}
|
|
971
1391
|
/**
|
|
972
|
-
* Sets the list of downstream
|
|
1392
|
+
* Sets the list of downstream addresses 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
1393
|
* @param domain - The domain name.
|
|
974
1394
|
* @param records - The list of records to set for the domain. A maximum of 10 records can be set.
|
|
975
1395
|
* @example
|
|
@@ -1084,6 +1504,138 @@ class Domains {
|
|
|
1084
1504
|
});
|
|
1085
1505
|
return data;
|
|
1086
1506
|
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Generate a batch of links that allow a user to log in as a domain administrator to their different domains.
|
|
1509
|
+
* @param domains - The list of domain names. Maximum of `1000` links per request.
|
|
1510
|
+
* @example
|
|
1511
|
+
* ```ts
|
|
1512
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1513
|
+
* const { results } = await mailchannels.domains.bulkCreateLoginLinks(['example.com', 'example2.com'])
|
|
1514
|
+
* ```
|
|
1515
|
+
*/
|
|
1516
|
+
async bulkCreateLoginLinks(domains) {
|
|
1517
|
+
const data = { results: [], error: null };
|
|
1518
|
+
if (!domains || !domains.length) {
|
|
1519
|
+
data.error = "No domains provided.";
|
|
1520
|
+
return data;
|
|
1521
|
+
}
|
|
1522
|
+
if (domains.length > 1e3) {
|
|
1523
|
+
data.error = "The maximum number of domains to create login links for is 1000.";
|
|
1524
|
+
return data;
|
|
1525
|
+
}
|
|
1526
|
+
const response = await this.mailchannels.post("/inbound/v1/domains/batch/login-link", {
|
|
1527
|
+
body: {
|
|
1528
|
+
domains: domains.map((domain) => ({ domain }))
|
|
1529
|
+
},
|
|
1530
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1531
|
+
data.error = getStatusError(response2, {
|
|
1532
|
+
[ErrorCode.BadRequest]: "Bad Request."
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
}).catch(() => null);
|
|
1536
|
+
if (!response) return data;
|
|
1537
|
+
data.results = response;
|
|
1538
|
+
return data;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
class Lists {
|
|
1543
|
+
constructor(mailchannels) {
|
|
1544
|
+
this.mailchannels = mailchannels;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Add item to account-level list
|
|
1548
|
+
* @param options - The options for the list entry to add.
|
|
1549
|
+
* @example
|
|
1550
|
+
* ```ts
|
|
1551
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1552
|
+
* const { entry } = await mailchannels.lists.addListEntry({
|
|
1553
|
+
* listName: 'safelist',
|
|
1554
|
+
* item: 'name@domain.com'
|
|
1555
|
+
* })
|
|
1556
|
+
* ```
|
|
1557
|
+
*/
|
|
1558
|
+
async addListEntry(options) {
|
|
1559
|
+
const { listName, item } = options;
|
|
1560
|
+
const data = { entry: null, error: null };
|
|
1561
|
+
if (!listName) {
|
|
1562
|
+
data.error = "No list name provided.";
|
|
1563
|
+
return data;
|
|
1564
|
+
}
|
|
1565
|
+
const response = await this.mailchannels.post(`/inbound/v1/lists/${listName}`, {
|
|
1566
|
+
body: { item },
|
|
1567
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1568
|
+
data.error = getStatusError(response2);
|
|
1569
|
+
}
|
|
1570
|
+
}).catch(() => null);
|
|
1571
|
+
if (!response) return data;
|
|
1572
|
+
data.entry = {
|
|
1573
|
+
action: response.action,
|
|
1574
|
+
item: response.item,
|
|
1575
|
+
type: response.item_type
|
|
1576
|
+
};
|
|
1577
|
+
return data;
|
|
1578
|
+
}
|
|
1579
|
+
/**
|
|
1580
|
+
* Get account-level list entries.
|
|
1581
|
+
* @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
|
|
1582
|
+
* @example
|
|
1583
|
+
* ```ts
|
|
1584
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1585
|
+
* const { entries } = await mailchannels.lists.listEntries('safelist')
|
|
1586
|
+
* ```
|
|
1587
|
+
*/
|
|
1588
|
+
async listEntries(listName) {
|
|
1589
|
+
const data = { entries: [], error: null };
|
|
1590
|
+
if (!listName) {
|
|
1591
|
+
data.error = "No list name provided.";
|
|
1592
|
+
return data;
|
|
1593
|
+
}
|
|
1594
|
+
const response = await this.mailchannels.get(`/inbound/v1/lists/${listName}`, {
|
|
1595
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1596
|
+
data.error = getStatusError(response2);
|
|
1597
|
+
}
|
|
1598
|
+
}).catch(() => null);
|
|
1599
|
+
if (!response) return data;
|
|
1600
|
+
data.entries = response.map(({ action, item, item_type }) => ({
|
|
1601
|
+
action,
|
|
1602
|
+
item,
|
|
1603
|
+
type: item_type
|
|
1604
|
+
}));
|
|
1605
|
+
return data;
|
|
1606
|
+
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Delete item from account-level list.
|
|
1609
|
+
* @param options - The options for the list entry to delete.
|
|
1610
|
+
* @example
|
|
1611
|
+
* ```ts
|
|
1612
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1613
|
+
* const { success } = await mailchannels.lists.deleteListEntry({
|
|
1614
|
+
* listName: 'safelist',
|
|
1615
|
+
* item: 'name@domain.com'
|
|
1616
|
+
* })
|
|
1617
|
+
* ```
|
|
1618
|
+
*/
|
|
1619
|
+
async deleteListEntry(options) {
|
|
1620
|
+
const { listName, item } = options;
|
|
1621
|
+
const data = { success: false, error: null };
|
|
1622
|
+
if (!listName) {
|
|
1623
|
+
data.error = "No list name provided.";
|
|
1624
|
+
return data;
|
|
1625
|
+
}
|
|
1626
|
+
await this.mailchannels.delete(`/inbound/v1/lists/${listName}`, {
|
|
1627
|
+
query: { item },
|
|
1628
|
+
ignoreResponseError: true,
|
|
1629
|
+
onResponse: async ({ response }) => {
|
|
1630
|
+
if (response.ok) {
|
|
1631
|
+
data.success = true;
|
|
1632
|
+
return;
|
|
1633
|
+
}
|
|
1634
|
+
data.error = getStatusError(response);
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
return data;
|
|
1638
|
+
}
|
|
1087
1639
|
}
|
|
1088
1640
|
|
|
1089
1641
|
class Users {
|
|
@@ -1256,93 +1808,71 @@ class Users {
|
|
|
1256
1808
|
}
|
|
1257
1809
|
}
|
|
1258
1810
|
|
|
1259
|
-
class
|
|
1811
|
+
class Service {
|
|
1260
1812
|
constructor(mailchannels) {
|
|
1261
1813
|
this.mailchannels = mailchannels;
|
|
1262
1814
|
}
|
|
1263
1815
|
/**
|
|
1264
|
-
*
|
|
1265
|
-
* @param options - The options for the list entry to add.
|
|
1816
|
+
* Retrieve the condition of the service
|
|
1266
1817
|
* @example
|
|
1267
1818
|
* ```ts
|
|
1268
1819
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1269
|
-
* const {
|
|
1270
|
-
* listName: 'safelist',
|
|
1271
|
-
* item: 'name@domain.com'
|
|
1272
|
-
* })
|
|
1820
|
+
* const { success } = await mailchannels.service.status()
|
|
1273
1821
|
* ```
|
|
1274
1822
|
*/
|
|
1275
|
-
async
|
|
1276
|
-
const {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
data.error = getStatusError(response2);
|
|
1823
|
+
async status() {
|
|
1824
|
+
const data = { success: false, error: null };
|
|
1825
|
+
await this.mailchannels.get("/inbound/v1/status", {
|
|
1826
|
+
ignoreResponseError: true,
|
|
1827
|
+
onResponse: async ({ response }) => {
|
|
1828
|
+
if (response.ok) {
|
|
1829
|
+
data.success = true;
|
|
1830
|
+
return;
|
|
1831
|
+
}
|
|
1832
|
+
data.error = getStatusError(response);
|
|
1286
1833
|
}
|
|
1287
|
-
})
|
|
1288
|
-
if (!response) return data;
|
|
1289
|
-
data.entry = {
|
|
1290
|
-
action: response.action,
|
|
1291
|
-
item: response.item,
|
|
1292
|
-
type: response.item_type
|
|
1293
|
-
};
|
|
1834
|
+
});
|
|
1294
1835
|
return data;
|
|
1295
1836
|
}
|
|
1296
1837
|
/**
|
|
1297
|
-
* Get
|
|
1298
|
-
* @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
|
|
1838
|
+
* Get a list of your subscriptions to MailChannels Inbound
|
|
1299
1839
|
* @example
|
|
1300
1840
|
* ```ts
|
|
1301
1841
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1302
|
-
* const {
|
|
1842
|
+
* const { subscriptions } = await mailchannels.service.subscriptions()
|
|
1303
1843
|
* ```
|
|
1304
1844
|
*/
|
|
1305
|
-
async
|
|
1306
|
-
const data = {
|
|
1307
|
-
|
|
1308
|
-
data.error = "No list name provided.";
|
|
1309
|
-
return data;
|
|
1310
|
-
}
|
|
1311
|
-
const response = await this.mailchannels.get(`/inbound/v1/lists/${listName}`, {
|
|
1845
|
+
async subscriptions() {
|
|
1846
|
+
const data = { subscriptions: [], error: null };
|
|
1847
|
+
const response = await this.mailchannels.get("/inbound/v1/subscriptions", {
|
|
1312
1848
|
onResponseError: async ({ response: response2 }) => {
|
|
1313
|
-
data.error = getStatusError(response2
|
|
1849
|
+
data.error = getStatusError(response2, {
|
|
1850
|
+
[ErrorCode.NotFound]: "We could not find a customer that matched the customerHandle."
|
|
1851
|
+
});
|
|
1314
1852
|
}
|
|
1315
|
-
}).catch(() =>
|
|
1316
|
-
|
|
1317
|
-
data.entries = response.map(({ action, item, item_type }) => ({
|
|
1318
|
-
action,
|
|
1319
|
-
item,
|
|
1320
|
-
type: item_type
|
|
1321
|
-
}));
|
|
1853
|
+
}).catch(() => []);
|
|
1854
|
+
data.subscriptions = response;
|
|
1322
1855
|
return data;
|
|
1323
1856
|
}
|
|
1324
1857
|
/**
|
|
1325
|
-
*
|
|
1326
|
-
* @param options - The options
|
|
1858
|
+
* Submit a false negative or false positive report.
|
|
1859
|
+
* @param options - The report options
|
|
1327
1860
|
* @example
|
|
1328
1861
|
* ```ts
|
|
1329
1862
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1330
|
-
* const { success } = await mailchannels.
|
|
1331
|
-
*
|
|
1332
|
-
* item: 'name@domain.com'
|
|
1863
|
+
* const { success, error } = await mailchannels.service.report({
|
|
1864
|
+
* // ...
|
|
1333
1865
|
* })
|
|
1334
1866
|
* ```
|
|
1335
1867
|
*/
|
|
1336
|
-
async
|
|
1337
|
-
const { listName, item } = options;
|
|
1868
|
+
async report(options) {
|
|
1338
1869
|
const data = { success: false, error: null };
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
ignoreResponseError: true,
|
|
1870
|
+
const { type, ...payload } = options;
|
|
1871
|
+
await this.mailchannels.post("/inbound/v1/report", {
|
|
1872
|
+
query: {
|
|
1873
|
+
report_type: type
|
|
1874
|
+
},
|
|
1875
|
+
body: payload,
|
|
1346
1876
|
onResponse: async ({ response }) => {
|
|
1347
1877
|
if (response.ok) {
|
|
1348
1878
|
data.success = true;
|
|
@@ -1355,4 +1885,4 @@ class Lists {
|
|
|
1355
1885
|
}
|
|
1356
1886
|
}
|
|
1357
1887
|
|
|
1358
|
-
export { Domains, Emails, Lists, Service, SubAccounts, Users, Webhooks };
|
|
1888
|
+
export { Domains, Emails, Lists, Metrics, Service, SubAccounts, Suppressions, Users, Webhooks };
|