mailchannels-sdk 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -39
- 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 +592 -95
- package/dist/shared/{mailchannels-sdk.BDB65ygx.d.mts → mailchannels-sdk.DUD1k4jz.d.mts} +587 -113
- package/dist/shared/{mailchannels-sdk.BDB65ygx.d.ts → mailchannels-sdk.DUD1k4jz.d.ts} +587 -113
- package/package.json +16 -17
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
|
|
667
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)
|
|
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 response = 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 response = 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 response = 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 {
|
|
@@ -1086,6 +1506,105 @@ class Domains {
|
|
|
1086
1506
|
}
|
|
1087
1507
|
}
|
|
1088
1508
|
|
|
1509
|
+
class Lists {
|
|
1510
|
+
constructor(mailchannels) {
|
|
1511
|
+
this.mailchannels = mailchannels;
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Add item to account-level list
|
|
1515
|
+
* @param options - The options for the list entry to add.
|
|
1516
|
+
* @example
|
|
1517
|
+
* ```ts
|
|
1518
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1519
|
+
* const { entry } = await mailchannels.lists.addListEntry({
|
|
1520
|
+
* listName: 'safelist',
|
|
1521
|
+
* item: 'name@domain.com'
|
|
1522
|
+
* })
|
|
1523
|
+
* ```
|
|
1524
|
+
*/
|
|
1525
|
+
async addListEntry(options) {
|
|
1526
|
+
const { listName, item } = options;
|
|
1527
|
+
const data = { entry: null, error: null };
|
|
1528
|
+
if (!listName) {
|
|
1529
|
+
data.error = "No list name provided.";
|
|
1530
|
+
return data;
|
|
1531
|
+
}
|
|
1532
|
+
const response = await this.mailchannels.post(`/inbound/v1/lists/${listName}`, {
|
|
1533
|
+
body: { item },
|
|
1534
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1535
|
+
data.error = getStatusError(response2);
|
|
1536
|
+
}
|
|
1537
|
+
}).catch(() => null);
|
|
1538
|
+
if (!response) return data;
|
|
1539
|
+
data.entry = {
|
|
1540
|
+
action: response.action,
|
|
1541
|
+
item: response.item,
|
|
1542
|
+
type: response.item_type
|
|
1543
|
+
};
|
|
1544
|
+
return data;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Get account-level list entries.
|
|
1548
|
+
* @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
|
|
1549
|
+
* @example
|
|
1550
|
+
* ```ts
|
|
1551
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1552
|
+
* const { entries } = await mailchannels.lists.listEntries('safelist')
|
|
1553
|
+
* ```
|
|
1554
|
+
*/
|
|
1555
|
+
async listEntries(listName) {
|
|
1556
|
+
const data = { entries: [], error: null };
|
|
1557
|
+
if (!listName) {
|
|
1558
|
+
data.error = "No list name provided.";
|
|
1559
|
+
return data;
|
|
1560
|
+
}
|
|
1561
|
+
const response = await this.mailchannels.get(`/inbound/v1/lists/${listName}`, {
|
|
1562
|
+
onResponseError: async ({ response: response2 }) => {
|
|
1563
|
+
data.error = getStatusError(response2);
|
|
1564
|
+
}
|
|
1565
|
+
}).catch(() => null);
|
|
1566
|
+
if (!response) return data;
|
|
1567
|
+
data.entries = response.map(({ action, item, item_type }) => ({
|
|
1568
|
+
action,
|
|
1569
|
+
item,
|
|
1570
|
+
type: item_type
|
|
1571
|
+
}));
|
|
1572
|
+
return data;
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Delete item from account-level list.
|
|
1576
|
+
* @param options - The options for the list entry to delete.
|
|
1577
|
+
* @example
|
|
1578
|
+
* ```ts
|
|
1579
|
+
* const mailchannels = new MailChannels('your-api-key')
|
|
1580
|
+
* const { success } = await mailchannels.lists.deleteListEntry({
|
|
1581
|
+
* listName: 'safelist',
|
|
1582
|
+
* item: 'name@domain.com'
|
|
1583
|
+
* })
|
|
1584
|
+
* ```
|
|
1585
|
+
*/
|
|
1586
|
+
async deleteListEntry(options) {
|
|
1587
|
+
const { listName, item } = options;
|
|
1588
|
+
const data = { success: false, error: null };
|
|
1589
|
+
if (!listName) {
|
|
1590
|
+
data.error = "No list name provided.";
|
|
1591
|
+
return data;
|
|
1592
|
+
}
|
|
1593
|
+
await this.mailchannels.delete(`/inbound/v1/lists/${listName}`, {
|
|
1594
|
+
query: { item },
|
|
1595
|
+
ignoreResponseError: true,
|
|
1596
|
+
onResponse: async ({ response }) => {
|
|
1597
|
+
if (response.ok) {
|
|
1598
|
+
data.success = true;
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
data.error = getStatusError(response);
|
|
1602
|
+
}
|
|
1603
|
+
});
|
|
1604
|
+
return data;
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1089
1608
|
class Users {
|
|
1090
1609
|
constructor(mailchannels) {
|
|
1091
1610
|
this.mailchannels = mailchannels;
|
|
@@ -1256,93 +1775,71 @@ class Users {
|
|
|
1256
1775
|
}
|
|
1257
1776
|
}
|
|
1258
1777
|
|
|
1259
|
-
class
|
|
1778
|
+
class Service {
|
|
1260
1779
|
constructor(mailchannels) {
|
|
1261
1780
|
this.mailchannels = mailchannels;
|
|
1262
1781
|
}
|
|
1263
1782
|
/**
|
|
1264
|
-
*
|
|
1265
|
-
* @param options - The options for the list entry to add.
|
|
1783
|
+
* Retrieve the condition of the service
|
|
1266
1784
|
* @example
|
|
1267
1785
|
* ```ts
|
|
1268
1786
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1269
|
-
* const {
|
|
1270
|
-
* listName: 'safelist',
|
|
1271
|
-
* item: 'name@domain.com'
|
|
1272
|
-
* })
|
|
1787
|
+
* const { success } = await mailchannels.service.status()
|
|
1273
1788
|
* ```
|
|
1274
1789
|
*/
|
|
1275
|
-
async
|
|
1276
|
-
const {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
data.error = getStatusError(response2);
|
|
1790
|
+
async status() {
|
|
1791
|
+
const data = { success: false, error: null };
|
|
1792
|
+
await this.mailchannels.get("/inbound/v1/status", {
|
|
1793
|
+
ignoreResponseError: true,
|
|
1794
|
+
onResponse: async ({ response }) => {
|
|
1795
|
+
if (response.ok) {
|
|
1796
|
+
data.success = true;
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
data.error = getStatusError(response);
|
|
1286
1800
|
}
|
|
1287
|
-
})
|
|
1288
|
-
if (!response) return data;
|
|
1289
|
-
data.entry = {
|
|
1290
|
-
action: response.action,
|
|
1291
|
-
item: response.item,
|
|
1292
|
-
type: response.item_type
|
|
1293
|
-
};
|
|
1801
|
+
});
|
|
1294
1802
|
return data;
|
|
1295
1803
|
}
|
|
1296
1804
|
/**
|
|
1297
|
-
* Get
|
|
1298
|
-
* @param listName - The name of the list to fetch. This can be a `blocklist`, `safelist`, `blacklist`, or `whitelist`.
|
|
1805
|
+
* Get a list of your subscriptions to MailChannels Inbound
|
|
1299
1806
|
* @example
|
|
1300
1807
|
* ```ts
|
|
1301
1808
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1302
|
-
* const {
|
|
1809
|
+
* const { subscriptions } = await mailchannels.service.subscriptions()
|
|
1303
1810
|
* ```
|
|
1304
1811
|
*/
|
|
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}`, {
|
|
1812
|
+
async subscriptions() {
|
|
1813
|
+
const data = { subscriptions: [], error: null };
|
|
1814
|
+
const response = await this.mailchannels.get("/inbound/v1/subscriptions", {
|
|
1312
1815
|
onResponseError: async ({ response: response2 }) => {
|
|
1313
|
-
data.error = getStatusError(response2
|
|
1816
|
+
data.error = getStatusError(response2, {
|
|
1817
|
+
[ErrorCode.NotFound]: "We could not find a customer that matched the customerHandle."
|
|
1818
|
+
});
|
|
1314
1819
|
}
|
|
1315
|
-
}).catch(() =>
|
|
1316
|
-
|
|
1317
|
-
data.entries = response.map(({ action, item, item_type }) => ({
|
|
1318
|
-
action,
|
|
1319
|
-
item,
|
|
1320
|
-
type: item_type
|
|
1321
|
-
}));
|
|
1820
|
+
}).catch(() => []);
|
|
1821
|
+
data.subscriptions = response;
|
|
1322
1822
|
return data;
|
|
1323
1823
|
}
|
|
1324
1824
|
/**
|
|
1325
|
-
*
|
|
1326
|
-
* @param options - The options
|
|
1825
|
+
* Submit a false negative or false positive report.
|
|
1826
|
+
* @param options - The report options
|
|
1327
1827
|
* @example
|
|
1328
1828
|
* ```ts
|
|
1329
1829
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1330
|
-
* const { success } = await mailchannels.
|
|
1331
|
-
*
|
|
1332
|
-
* item: 'name@domain.com'
|
|
1830
|
+
* const { success, error } = await mailchannels.service.report({
|
|
1831
|
+
* // ...
|
|
1333
1832
|
* })
|
|
1334
1833
|
* ```
|
|
1335
1834
|
*/
|
|
1336
|
-
async
|
|
1337
|
-
const { listName, item } = options;
|
|
1835
|
+
async report(options) {
|
|
1338
1836
|
const data = { success: false, error: null };
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
ignoreResponseError: true,
|
|
1837
|
+
const { type, ...payload } = options;
|
|
1838
|
+
await this.mailchannels.post("/inbound/v1/report", {
|
|
1839
|
+
query: {
|
|
1840
|
+
report_type: type
|
|
1841
|
+
},
|
|
1842
|
+
body: payload,
|
|
1346
1843
|
onResponse: async ({ response }) => {
|
|
1347
1844
|
if (response.ok) {
|
|
1348
1845
|
data.success = true;
|
|
@@ -1355,4 +1852,4 @@ class Lists {
|
|
|
1355
1852
|
}
|
|
1356
1853
|
}
|
|
1357
1854
|
|
|
1358
|
-
export { Domains, Emails, Lists, Service, SubAccounts, Users, Webhooks };
|
|
1855
|
+
export { Domains, Emails, Lists, Metrics, Service, SubAccounts, Suppressions, Users, Webhooks };
|