mailchannels-sdk 0.8.0-0 → 0.8.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/LICENSE +1 -1
- package/README.md +2 -6
- package/dist/mailchannels.d.mts +124 -97
- package/dist/mailchannels.mjs +211 -55
- package/package.json +17 -15
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
[![npm version][npm-version-src]][npm-version-href]
|
|
6
6
|
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
7
|
-
[![codecov][codecov-coverage-src]][codecov-coverage-href]
|
|
8
7
|
|
|
9
8
|
> Built and tested against Email API `0.21.1`
|
|
10
9
|
|
|
@@ -109,7 +108,7 @@ This package includes a local MailChannels simulator you can run via the CLI. It
|
|
|
109
108
|
|
|
110
109
|
| API | Source |
|
|
111
110
|
| ----------- | -------------------------------------------------------------------------------------------------------------- |
|
|
112
|
-
| Email API | [`src/simulator/email-api.mjs`](https://
|
|
111
|
+
| Email API | [`src/simulator/email-api.mjs`](https://bitbucket.org/mailchannels/mailchannels-email-api-sdk-js/src/main/src/simulator/email-api.mjs) |
|
|
113
112
|
|
|
114
113
|
> [!IMPORTANT]
|
|
115
114
|
> The simulator approximates the MailChannels service for local development and testing. It is not a production implementation and may differ from the live service.
|
|
@@ -212,7 +211,7 @@ pnpm parity:fixtures
|
|
|
212
211
|
pnpm simulate
|
|
213
212
|
|
|
214
213
|
# Run a playground script
|
|
215
|
-
|
|
214
|
+
pnpx jiti playground/emails/send.ts
|
|
216
215
|
|
|
217
216
|
# Release new version
|
|
218
217
|
pnpm release
|
|
@@ -226,6 +225,3 @@ pnpm release
|
|
|
226
225
|
|
|
227
226
|
[npm-downloads-src]: https://img.shields.io/npm/dm/mailchannels-sdk.svg?style=flat&colorA=070a30&colorB=35a047
|
|
228
227
|
[npm-downloads-href]: https://npmjs.com/package/mailchannels-sdk
|
|
229
|
-
|
|
230
|
-
[codecov-coverage-src]: https://img.shields.io/codecov/c/github/yizack/mailchannels?style=flat&colorA=070a30&token=HTSBRHSJ5M
|
|
231
|
-
[codecov-coverage-href]: https://codecov.io/gh/Yizack/mailchannels
|
package/dist/mailchannels.d.mts
CHANGED
|
@@ -20,13 +20,24 @@ interface MailChannelsClientOptions {
|
|
|
20
20
|
* @default false
|
|
21
21
|
*/
|
|
22
22
|
retry?: number | false;
|
|
23
|
+
/**
|
|
24
|
+
* Request timeout in milliseconds.
|
|
25
|
+
* Set to `false` or `0` to disable timeout handling.
|
|
26
|
+
* @default 120000
|
|
27
|
+
*/
|
|
28
|
+
timeout?: number | false;
|
|
29
|
+
/**
|
|
30
|
+
* Abort signal applied to requests made by the client.
|
|
31
|
+
*/
|
|
32
|
+
signal?: AbortSignal;
|
|
23
33
|
}
|
|
24
34
|
declare class MailChannelsClient {
|
|
25
35
|
#private;
|
|
26
36
|
private static readonly DEFAULT_BASE_URL;
|
|
37
|
+
private static readonly DEFAULT_TIMEOUT;
|
|
27
38
|
private readonly options;
|
|
28
39
|
constructor(key: string, options?: MailChannelsClientOptions);
|
|
29
|
-
protected _fetch<T>(path: string, options
|
|
40
|
+
protected _fetch<T>(path: string, options: FetchOptions<"json">): Promise<T>;
|
|
30
41
|
post<T>(path: string, options?: Omit<FetchOptions<"json">, "method">): Promise<T>;
|
|
31
42
|
get<T>(path: string, options?: Omit<FetchOptions<"json">, "method">): Promise<T>;
|
|
32
43
|
delete<T>(path: string, options?: Omit<FetchOptions<"json">, "method">): Promise<T>;
|
|
@@ -96,7 +107,15 @@ interface EmailsSendAttachment {
|
|
|
96
107
|
/**
|
|
97
108
|
* The MIME type of the attachment.
|
|
98
109
|
*/
|
|
99
|
-
type
|
|
110
|
+
type?: string;
|
|
111
|
+
/**
|
|
112
|
+
* The `Content-ID` header value for inline attachments, referenced from HTML with `cid:`.
|
|
113
|
+
*/
|
|
114
|
+
contentId?: string;
|
|
115
|
+
/**
|
|
116
|
+
* The `Content-Disposition` header value for the attachment.
|
|
117
|
+
*/
|
|
118
|
+
disposition?: "attachment" | "inline";
|
|
100
119
|
}
|
|
101
120
|
interface EmailsSendTracking {
|
|
102
121
|
/**
|
|
@@ -211,7 +230,7 @@ interface EmailsSendOptionsBase {
|
|
|
211
230
|
/**
|
|
212
231
|
* An array of attachments to be sent with the email.
|
|
213
232
|
*/
|
|
214
|
-
attachments?: EmailsSendAttachment[];
|
|
233
|
+
attachments?: (EmailsSendAttachment | Promise<EmailsSendAttachment>)[];
|
|
215
234
|
/**
|
|
216
235
|
* The campaign identifier. If specified, this ID will be included in all relevant webhooks. It can be up to 48 UTF-8 characters long and must not contain spaces.
|
|
217
236
|
*/
|
|
@@ -438,7 +457,7 @@ type EmailsSendResponse = DataResponse<{
|
|
|
438
457
|
status: "sent" | "failed";
|
|
439
458
|
}[];
|
|
440
459
|
}>;
|
|
441
|
-
type
|
|
460
|
+
type EmailsQueueResponse = DataResponse<{
|
|
442
461
|
/**
|
|
443
462
|
* ISO 8601 timestamp when the request was queued for processing.
|
|
444
463
|
*/
|
|
@@ -448,6 +467,7 @@ type EmailsSendAsyncResponse = DataResponse<{
|
|
|
448
467
|
*/
|
|
449
468
|
requestId: string;
|
|
450
469
|
}>;
|
|
470
|
+
type EmailsSendAsyncResponse = EmailsQueueResponse;
|
|
451
471
|
declare class Emails {
|
|
452
472
|
protected mailchannels: MailChannelsClient;
|
|
453
473
|
constructor(mailchannels: MailChannelsClient);
|
|
@@ -478,7 +498,7 @@ declare class Emails {
|
|
|
478
498
|
* @example
|
|
479
499
|
* ```ts
|
|
480
500
|
* const mailchannels = new MailChannels('your-api-key')
|
|
481
|
-
* const { data, error } = await mailchannels.emails.
|
|
501
|
+
* const { data, error } = await mailchannels.emails.queue({
|
|
482
502
|
* to: 'to@example.com',
|
|
483
503
|
* from: 'from@example.com',
|
|
484
504
|
* subject: 'Test',
|
|
@@ -486,7 +506,11 @@ declare class Emails {
|
|
|
486
506
|
* })
|
|
487
507
|
* ```
|
|
488
508
|
*/
|
|
489
|
-
|
|
509
|
+
queue(options: EmailsSendOptions): Promise<EmailsQueueResponse>;
|
|
510
|
+
/**
|
|
511
|
+
* @deprecated Use `queue` instead.
|
|
512
|
+
*/
|
|
513
|
+
sendAsync(options: EmailsSendOptions): Promise<EmailsQueueResponse>;
|
|
490
514
|
}
|
|
491
515
|
interface DomainsDkimCreateOptions {
|
|
492
516
|
/**
|
|
@@ -578,10 +602,6 @@ interface DomainsCheckOptions {
|
|
|
578
602
|
* 6. If `selector` is present and `domain` is not, the domain will be taken from the domain field of the request.
|
|
579
603
|
*/
|
|
580
604
|
dkim?: DomainsCheck[] | DomainsCheck;
|
|
581
|
-
/**
|
|
582
|
-
* Domain used for sending emails. If `dkim` settings are not provided, or `dkim` settings are provided with no `domain`, the stored dkim settings for this domain will be used.
|
|
583
|
-
*/
|
|
584
|
-
domain: string;
|
|
585
605
|
/**
|
|
586
606
|
* Used exclusively for [Domain Lockdown](https://support.mailchannels.com/hc/en-us/articles/16918954360845-Secure-your-domain-name-against-spoofing-with-Domain-Lockdown) verification. If you're not using senderid to associate your domain with your account, you can disregard this field. The corresponding value is included in the `X-MailChannels-SenderId` header of emails sent via MailChannels.
|
|
587
607
|
*/
|
|
@@ -676,7 +696,7 @@ interface DomainsDkimListOptions {
|
|
|
676
696
|
}
|
|
677
697
|
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
678
698
|
type DomainsDkimListResponse = DataResponse<Optional<DomainsDkimKey, "dnsRecords">[]>;
|
|
679
|
-
interface
|
|
699
|
+
interface DomainsDkimUpdateStatusOptions {
|
|
680
700
|
/**
|
|
681
701
|
* Selector of the DKIM key pair to update. Must be a maximum of 63 characters.
|
|
682
702
|
*/
|
|
@@ -707,22 +727,22 @@ declare class Domains {
|
|
|
707
727
|
constructor(mailchannels: MailChannelsClient);
|
|
708
728
|
/**
|
|
709
729
|
* 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.
|
|
730
|
+
* @param domain - Domain used for sending emails. If `dkim` settings are not provided, or `dkim` settings are provided with no `domain`, the stored dkim settings for this domain will be used.
|
|
710
731
|
* @param options - The domain options to check.
|
|
711
732
|
* @example
|
|
712
733
|
* ```ts
|
|
713
734
|
* const mailchannels = new MailChannels('your-api-key')
|
|
714
|
-
* const { data, error } = await mailchannels.domains.check({
|
|
735
|
+
* const { data, error } = await mailchannels.domains.check('example.com', {
|
|
715
736
|
* dkim: [{
|
|
716
737
|
* domain: 'example.com',
|
|
717
738
|
* privateKey: 'your-private-key',
|
|
718
739
|
* selector: 'mailchannels'
|
|
719
740
|
* }],
|
|
720
|
-
* domain: 'example.com',
|
|
721
741
|
* senderId: 'sender-id'
|
|
722
742
|
* })
|
|
723
743
|
* ```
|
|
724
744
|
*/
|
|
725
|
-
check(
|
|
745
|
+
check(domain: string, options?: DomainsCheckOptions): Promise<DomainsCheckResponse>;
|
|
726
746
|
}
|
|
727
747
|
declare class DomainsDkim {
|
|
728
748
|
private mailchannels;
|
|
@@ -760,12 +780,12 @@ declare class DomainsDkim {
|
|
|
760
780
|
* @example
|
|
761
781
|
* ```ts
|
|
762
782
|
* const mailchannels = new MailChannels('your-api-key')
|
|
763
|
-
* const { success, error } = await mailchannels.domains.dkim.
|
|
783
|
+
* const { success, error } = await mailchannels.domains.dkim.updateStatus('example.com', {
|
|
764
784
|
* selector: 'mailchannels',
|
|
765
785
|
* status: 'retired'
|
|
766
786
|
* })
|
|
767
787
|
*/
|
|
768
|
-
|
|
788
|
+
updateStatus(domain: string, options: DomainsDkimUpdateStatusOptions): Promise<SuccessResponse>;
|
|
769
789
|
/**
|
|
770
790
|
* Rotate an active DKIM key pair. Mark the original key as `rotated`, and create a new key pair with the required new key selector, reusing the same algorithm and key length. The rotated key remains valid for signing for a 3-day grace period, and is automatically changed to `retired` 2 weeks after rotation. Publish the new key to its DNS TXT record before rotated key expires for signing as emails sent with an unpublished key will fail DKIM validation by receiving providers. After the grace period, only the new key is valid for signing if published.
|
|
771
791
|
* @param domain - The domain the DKIM key belongs to.
|
|
@@ -832,6 +852,78 @@ type WebhooksValidateResponse = DataResponse<{
|
|
|
832
852
|
} | null;
|
|
833
853
|
}[];
|
|
834
854
|
}>;
|
|
855
|
+
type WebhookEventType = "processed" | "delivered" | "open" | "click" | "hard-bounced" | "soft-bounced" | "dropped" | "complained" | "unsubscribed" | "test";
|
|
856
|
+
interface WebhookEventBase<T extends WebhookEventType> {
|
|
857
|
+
/**
|
|
858
|
+
* The sender's email address
|
|
859
|
+
*/
|
|
860
|
+
email?: string;
|
|
861
|
+
/**
|
|
862
|
+
* The MailChannels account ID that generated the webhook.
|
|
863
|
+
* If the message was sent by a sub-account, this field contains the sub-account handle.
|
|
864
|
+
*/
|
|
865
|
+
customerHandle: string;
|
|
866
|
+
/**
|
|
867
|
+
* The Unix timestamp (in seconds) when the event occurred; the timezone is always UTC
|
|
868
|
+
*/
|
|
869
|
+
timestamp: number;
|
|
870
|
+
/**
|
|
871
|
+
* The Message-Id of the message that generated the event
|
|
872
|
+
*/
|
|
873
|
+
smtpId?: string;
|
|
874
|
+
/**
|
|
875
|
+
* The type of event that occurred
|
|
876
|
+
*/
|
|
877
|
+
event: T;
|
|
878
|
+
/**
|
|
879
|
+
* A unique identifier generated to track the original HTTP request
|
|
880
|
+
*/
|
|
881
|
+
requestId?: string;
|
|
882
|
+
/**
|
|
883
|
+
* The campaign identifier for the message that generated the event
|
|
884
|
+
*/
|
|
885
|
+
campaignId?: string;
|
|
886
|
+
/**
|
|
887
|
+
* The recipients of the message
|
|
888
|
+
*/
|
|
889
|
+
recipients?: string[];
|
|
890
|
+
}
|
|
891
|
+
interface WebhookEventProcessed extends WebhookEventBase<"processed"> {}
|
|
892
|
+
interface WebhookEventDelivered extends WebhookEventBase<"delivered"> {}
|
|
893
|
+
interface WebhookEventWithTracking {
|
|
894
|
+
/**
|
|
895
|
+
* The User-Agent header given when the recipient opened the message
|
|
896
|
+
*/
|
|
897
|
+
userAgent?: string;
|
|
898
|
+
/**
|
|
899
|
+
* The IP address of the host that made the HTTP request
|
|
900
|
+
*/
|
|
901
|
+
ip?: string;
|
|
902
|
+
}
|
|
903
|
+
interface WebhookEventOpen extends WebhookEventBase<"open">, WebhookEventWithTracking {}
|
|
904
|
+
interface WebhookEventClick extends WebhookEventBase<"click">, WebhookEventWithTracking {
|
|
905
|
+
/**
|
|
906
|
+
* The URL that was clicked by the recipient
|
|
907
|
+
*/
|
|
908
|
+
url?: string;
|
|
909
|
+
}
|
|
910
|
+
interface WebhookEventWithStatus {
|
|
911
|
+
/**
|
|
912
|
+
* The SMTP status code that caused the bounce
|
|
913
|
+
*/
|
|
914
|
+
status?: string;
|
|
915
|
+
/**
|
|
916
|
+
* A human-readable explanation of why the message hard-bounced
|
|
917
|
+
*/
|
|
918
|
+
reason?: string;
|
|
919
|
+
}
|
|
920
|
+
interface WebhookEventHardBounced extends WebhookEventBase<"hard-bounced">, WebhookEventWithStatus {}
|
|
921
|
+
interface WebhookEventSoftBounced extends WebhookEventBase<"soft-bounced">, WebhookEventWithStatus {}
|
|
922
|
+
interface WebhookEventDropped extends WebhookEventBase<"dropped">, WebhookEventWithStatus {}
|
|
923
|
+
interface WebhookEventComplained extends WebhookEventBase<"complained"> {}
|
|
924
|
+
interface WebhookEventUnsubscribed extends WebhookEventBase<"unsubscribed"> {}
|
|
925
|
+
interface WebhookEventTest extends Omit<WebhookEventBase<"test">, "recipients" | "campaignId"> {}
|
|
926
|
+
type WebhookEvent = WebhookEventProcessed | WebhookEventDelivered | WebhookEventOpen | WebhookEventClick | WebhookEventHardBounced | WebhookEventSoftBounced | WebhookEventDropped | WebhookEventComplained | WebhookEventUnsubscribed | WebhookEventTest;
|
|
835
927
|
interface WebhooksVerifyOptions {
|
|
836
928
|
/**
|
|
837
929
|
* The raw body of the incoming webhook request as a string. This should be the exact payload received from the webhook, without any modifications or parsing, to ensure accurate signature verification.
|
|
@@ -855,6 +947,7 @@ interface WebhooksVerifyOptions {
|
|
|
855
947
|
*/
|
|
856
948
|
cache?: boolean;
|
|
857
949
|
}
|
|
950
|
+
type WebhooksVerifyResponse = DataResponse<WebhookEvent[]>;
|
|
858
951
|
type WebhooksBatchStatus = "1xx" | "2xx" | "3xx" | "4xx" | "5xx" | "no_response";
|
|
859
952
|
type WebhooksBatchResponseStatus = "1xx_response" | "2xx_response" | "3xx_response" | "4xx_response" | "5xx_response" | "no_response";
|
|
860
953
|
interface WebhooksBatchesOptions {
|
|
@@ -963,10 +1056,10 @@ declare class Webhooks {
|
|
|
963
1056
|
* @example
|
|
964
1057
|
* ```ts
|
|
965
1058
|
* const mailchannels = new MailChannels('your-api-key')
|
|
966
|
-
* const { success, error } = mailchannels.webhooks.
|
|
1059
|
+
* const { success, error } = await mailchannels.webhooks.create('https://example.com/api/webhooks/mailchannels')
|
|
967
1060
|
* ```
|
|
968
1061
|
*/
|
|
969
|
-
|
|
1062
|
+
create(endpoint: string): Promise<SuccessResponse>;
|
|
970
1063
|
/**
|
|
971
1064
|
* Retrieves all registered webhook endpoints associated with the customer.
|
|
972
1065
|
* @example
|
|
@@ -981,10 +1074,10 @@ declare class Webhooks {
|
|
|
981
1074
|
* @example
|
|
982
1075
|
* ```ts
|
|
983
1076
|
* const mailchannels = new MailChannels('your-api-key')
|
|
984
|
-
* const { success, error } = await mailchannels.webhooks.
|
|
1077
|
+
* const { success, error } = await mailchannels.webhooks.deleteAll()
|
|
985
1078
|
* ```
|
|
986
1079
|
*/
|
|
987
|
-
|
|
1080
|
+
deleteAll(): Promise<SuccessResponse>;
|
|
988
1081
|
/**
|
|
989
1082
|
* Retrieves the public key used to verify signatures on incoming webhook payloads.
|
|
990
1083
|
* @param id - The ID of the key.
|
|
@@ -1010,20 +1103,20 @@ declare class Webhooks {
|
|
|
1010
1103
|
* @param options - The options for verifying the webhook.
|
|
1011
1104
|
* @example
|
|
1012
1105
|
* ```ts
|
|
1013
|
-
* const
|
|
1106
|
+
* const { data, error } = await Webhooks.verify({ payload: rawBody, headers })
|
|
1014
1107
|
* ```
|
|
1015
1108
|
*/
|
|
1016
|
-
static verify(options: WebhooksVerifyOptions): Promise<
|
|
1109
|
+
static verify(options: WebhooksVerifyOptions): Promise<WebhooksVerifyResponse>;
|
|
1017
1110
|
/**
|
|
1018
1111
|
* Verifies the authenticity of incoming webhook requests by validating their signatures using the provided options.
|
|
1019
1112
|
* @param options - The options for verifying the webhook.
|
|
1020
1113
|
* @example
|
|
1021
1114
|
* ```ts
|
|
1022
1115
|
* const mailchannels = new MailChannels('your-api-key')
|
|
1023
|
-
* const
|
|
1116
|
+
* const { data, error } = await mailchannels.webhooks.verify({ payload: rawBody, headers })
|
|
1024
1117
|
* ```
|
|
1025
1118
|
*/
|
|
1026
|
-
verify(options: WebhooksVerifyOptions): Promise<
|
|
1119
|
+
verify(options: WebhooksVerifyOptions): Promise<WebhooksVerifyResponse>;
|
|
1027
1120
|
/**
|
|
1028
1121
|
* Retrieves paged webhook batches associated with the customer. The time range specified by `createdAfter` and `createdBefore` must not exceed 31 days. If neither is specified, the default time range is the last 3 days.
|
|
1029
1122
|
* @param options - The options for listing webhook batches.
|
|
@@ -1664,79 +1757,13 @@ declare class Suppressions {
|
|
|
1664
1757
|
*/
|
|
1665
1758
|
list(options?: SuppressionsListOptions): Promise<SuppressionsListResponse>;
|
|
1666
1759
|
}
|
|
1667
|
-
type
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
/**
|
|
1674
|
-
* The MailChannels account ID that generated the webhook.
|
|
1675
|
-
* If the message was sent by a sub-account, this field contains the sub-account handle.
|
|
1676
|
-
*/
|
|
1677
|
-
customer_handle: string;
|
|
1678
|
-
/**
|
|
1679
|
-
* The Unix timestamp (in seconds) when the event occurred; the timezone is always UTC
|
|
1680
|
-
*/
|
|
1681
|
-
timestamp: number;
|
|
1682
|
-
/**
|
|
1683
|
-
* The Message-Id of the message that generated the event
|
|
1684
|
-
*/
|
|
1685
|
-
smtp_id?: string;
|
|
1686
|
-
/**
|
|
1687
|
-
* The type of event that occurred
|
|
1688
|
-
*/
|
|
1689
|
-
event: T;
|
|
1690
|
-
/**
|
|
1691
|
-
* A unique identifier generated to track the original HTTP request
|
|
1692
|
-
*/
|
|
1693
|
-
request_id?: string;
|
|
1694
|
-
/**
|
|
1695
|
-
* The campaign identifier for the message that generated the event
|
|
1696
|
-
*/
|
|
1697
|
-
campaign_id?: string;
|
|
1698
|
-
/**
|
|
1699
|
-
* The recipients of the message
|
|
1700
|
-
*/
|
|
1701
|
-
recipients?: string[];
|
|
1702
|
-
}
|
|
1703
|
-
interface WebhookEventProcessed extends WebhookEventBase<"processed"> {}
|
|
1704
|
-
interface WebhookEventDelivered extends WebhookEventBase<"delivered"> {}
|
|
1705
|
-
interface WebhookEventWithTracking {
|
|
1706
|
-
/**
|
|
1707
|
-
* The User-Agent header given when the recipient opened the message
|
|
1708
|
-
*/
|
|
1709
|
-
user_agent?: string;
|
|
1710
|
-
/**
|
|
1711
|
-
* The IP address of the host that made the HTTP request
|
|
1712
|
-
*/
|
|
1713
|
-
ip?: string;
|
|
1760
|
+
type AttachmentOptions = Omit<EmailsSendAttachment, "content">;
|
|
1761
|
+
declare class Attachment {
|
|
1762
|
+
static fromBytes(data: ArrayBuffer | Uint8Array, options: AttachmentOptions): EmailsSendAttachment;
|
|
1763
|
+
static fromFile(path: string | URL, options?: Partial<AttachmentOptions>): Promise<EmailsSendAttachment>;
|
|
1764
|
+
static fromUrl(url: string, options?: Partial<AttachmentOptions>): Promise<EmailsSendAttachment>;
|
|
1765
|
+
static inlineFile(path: string | URL, options?: Partial<Omit<AttachmentOptions, "disposition">>): Promise<EmailsSendAttachment>;
|
|
1714
1766
|
}
|
|
1715
|
-
interface WebhookEventOpen extends WebhookEventBase<"open">, WebhookEventWithTracking {}
|
|
1716
|
-
interface WebhookEventClick extends WebhookEventBase<"click">, WebhookEventWithTracking {
|
|
1717
|
-
/**
|
|
1718
|
-
* The URL that was clicked by the recipient
|
|
1719
|
-
*/
|
|
1720
|
-
url?: string;
|
|
1721
|
-
}
|
|
1722
|
-
interface WebhookEventWithStatus {
|
|
1723
|
-
/**
|
|
1724
|
-
* The SMTP status code that caused the bounce
|
|
1725
|
-
*/
|
|
1726
|
-
status?: string;
|
|
1727
|
-
/**
|
|
1728
|
-
* A human-readable explanation of why the message hard-bounced
|
|
1729
|
-
*/
|
|
1730
|
-
reason?: string;
|
|
1731
|
-
}
|
|
1732
|
-
interface WebhookEventHardBounced extends WebhookEventBase<"hard-bounced">, WebhookEventWithStatus {}
|
|
1733
|
-
interface WebhookEventSoftBounced extends WebhookEventBase<"soft-bounced">, WebhookEventWithStatus {}
|
|
1734
|
-
interface WebhookEventDropped extends WebhookEventBase<"dropped">, WebhookEventWithStatus {}
|
|
1735
|
-
interface WebhookEventComplained extends WebhookEventBase<"complained"> {}
|
|
1736
|
-
interface WebhookEventUnsubscribed extends WebhookEventBase<"unsubscribed"> {}
|
|
1737
|
-
interface WebhookEventTest extends Omit<WebhookEventBase<"test">, "recipients" | "campaign_id"> {}
|
|
1738
|
-
type WebhookEvent = WebhookEventProcessed | WebhookEventDelivered | WebhookEventOpen | WebhookEventClick | WebhookEventHardBounced | WebhookEventSoftBounced | WebhookEventDropped | WebhookEventComplained | WebhookEventUnsubscribed | WebhookEventTest;
|
|
1739
|
-
type WebhookEvents = WebhookEvent[];
|
|
1740
1767
|
declare class MailChannels extends MailChannelsClient {
|
|
1741
1768
|
readonly emails: Emails;
|
|
1742
1769
|
readonly domains: Domains;
|
|
@@ -1746,4 +1773,4 @@ declare class MailChannels extends MailChannelsClient {
|
|
|
1746
1773
|
readonly suppressions: Suppressions;
|
|
1747
1774
|
constructor(key: string, options?: MailChannelsClientOptions);
|
|
1748
1775
|
}
|
|
1749
|
-
export { DataResponse, Domains, DomainsCheckOptions, DomainsCheckResponse, DomainsCheckVerdict, DomainsDkimCreateOptions, DomainsDkimCreateResponse, DomainsDkimKey, DomainsDkimKeyStatus, DomainsDkimListOptions, DomainsDkimListResponse, DomainsDkimRotateOptions, DomainsDkimRotateResponse,
|
|
1776
|
+
export { Attachment, type DataResponse, Domains, type DomainsCheckOptions, type DomainsCheckResponse, type DomainsCheckVerdict, type DomainsDkimCreateOptions, type DomainsDkimCreateResponse, type DomainsDkimKey, type DomainsDkimKeyStatus, type DomainsDkimListOptions, type DomainsDkimListResponse, type DomainsDkimRotateOptions, type DomainsDkimRotateResponse, type DomainsDkimUpdateStatusOptions, Emails, type EmailsQueueResponse, type EmailsSendAsyncResponse, type EmailsSendAttachment, type EmailsSendContent, type EmailsSendDkim, type EmailsSendOptions, type EmailsSendPersonalization, type EmailsSendRecipient, type EmailsSendRecipientInput, type EmailsSendResponse, type EmailsSendTemplate, type EmailsSendTemplateType, type EmailsSendTemplateValue, type EmailsSendTracking, type ErrorResponse, MailChannels, MailChannelsClient, type MailChannelsClientOptions, Metrics, type MetricsBucket, type MetricsEngagement, type MetricsEngagementResponse, type MetricsOptions, type MetricsPerformance, type MetricsPerformanceResponse, type MetricsRecipientBehaviour, type MetricsRecipientBehaviourResponse, type MetricsSenders, type MetricsSendersOptions, type MetricsSendersResponse, type MetricsSendersType, type MetricsUsageResponse, type MetricsVolume, type MetricsVolumeResponse, SubAccounts, type SubAccountsAccount, type SubAccountsApiKey, type SubAccountsCreateApiKeyResponse, type SubAccountsCreateResponse, type SubAccountsCreateSmtpPasswordResponse, type SubAccountsLimit, type SubAccountsLimitResponse, type SubAccountsListApiKeyOptions, type SubAccountsListApiKeyResponse, type SubAccountsListOptions, type SubAccountsListResponse, type SubAccountsListSmtpPasswordResponse, type SubAccountsSmtpPassword, type SubAccountsUsage, type SubAccountsUsageResponse, type SuccessResponse, Suppressions, type SuppressionsCreateOptions, type SuppressionsListEntry, type SuppressionsListOptions, type SuppressionsListResponse, type SuppressionsSource, type SuppressionsTypes, type WebhookEvent, type WebhookEventClick, type WebhookEventComplained, type WebhookEventDelivered, type WebhookEventDropped, type WebhookEventHardBounced, type WebhookEventOpen, type WebhookEventProcessed, type WebhookEventSoftBounced, type WebhookEventTest, type WebhookEventType, type WebhookEventUnsubscribed, Webhooks, type WebhooksBatch, type WebhooksBatchResponseStatus, type WebhooksBatchStatus, type WebhooksBatchesOptions, type WebhooksBatchesResponse, type WebhooksListResponse, type WebhooksResendBatch, type WebhooksResendBatchResponse, type WebhooksSigningKeyResponse, type WebhooksValidateResponse, type WebhooksVerifyOptions, type WebhooksVerifyResponse };
|
package/dist/mailchannels.mjs
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { $fetch } from "ofetch";
|
|
2
2
|
import { subtle } from "node:crypto";
|
|
3
3
|
import { Buffer } from "node:buffer";
|
|
4
|
-
|
|
4
|
+
import { basename } from "node:path";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import mime from "mime";
|
|
7
|
+
var version = "0.8.0";
|
|
5
8
|
var MailChannelsClient = class MailChannelsClient {
|
|
6
9
|
static DEFAULT_BASE_URL = "https://api.mailchannels.net";
|
|
10
|
+
static DEFAULT_TIMEOUT = 12e4;
|
|
7
11
|
options;
|
|
8
12
|
#headers;
|
|
9
13
|
constructor(key, options = {}) {
|
|
10
14
|
if (!key) throw new Error("Missing MailChannels API key.");
|
|
11
15
|
this.options = {
|
|
12
16
|
baseUrl: options.baseUrl || MailChannelsClient.DEFAULT_BASE_URL,
|
|
13
|
-
retry: options.retry ?? false
|
|
17
|
+
retry: options.retry ?? false,
|
|
18
|
+
signal: options.signal,
|
|
19
|
+
timeout: options.timeout ?? MailChannelsClient.DEFAULT_TIMEOUT
|
|
14
20
|
};
|
|
15
21
|
this.#headers = {
|
|
16
22
|
"X-API-Key": key,
|
|
@@ -20,13 +26,16 @@ var MailChannelsClient = class MailChannelsClient {
|
|
|
20
26
|
};
|
|
21
27
|
}
|
|
22
28
|
async _fetch(path, options) {
|
|
29
|
+
const { headers, signal = this.options.signal, ...fetchOptions } = options;
|
|
23
30
|
return $fetch(path, {
|
|
24
31
|
baseURL: this.options.baseUrl,
|
|
25
32
|
retry: this.options.retry,
|
|
26
|
-
|
|
33
|
+
signal,
|
|
34
|
+
timeout: this.options.timeout === false ? void 0 : this.options.timeout,
|
|
35
|
+
...fetchOptions,
|
|
27
36
|
headers: {
|
|
28
37
|
...this.#headers,
|
|
29
|
-
...
|
|
38
|
+
...headers
|
|
30
39
|
}
|
|
31
40
|
});
|
|
32
41
|
}
|
|
@@ -85,7 +94,6 @@ const validatePagination = (pagination = {}) => {
|
|
|
85
94
|
if (typeof offset === "number" && offset < 0) return createError("Offset must be greater than or equal to 0.");
|
|
86
95
|
return null;
|
|
87
96
|
};
|
|
88
|
-
const stripPemHeaders = (pem) => pem.replace(/-----[^-]+-----|\s|#.*$/gm, "");
|
|
89
97
|
const clean = (data) => {
|
|
90
98
|
if (Array.isArray(data)) {
|
|
91
99
|
const result = [];
|
|
@@ -108,25 +116,6 @@ const clean = (data) => {
|
|
|
108
116
|
}
|
|
109
117
|
return data;
|
|
110
118
|
};
|
|
111
|
-
const mapBuckets = (arr) => {
|
|
112
|
-
return arr.map(({ count, period_start }) => ({
|
|
113
|
-
count,
|
|
114
|
-
periodStart: period_start
|
|
115
|
-
}));
|
|
116
|
-
};
|
|
117
|
-
const mapDkimKey = (key) => ({
|
|
118
|
-
algorithm: key.algorithm,
|
|
119
|
-
createdAt: key.created_at,
|
|
120
|
-
dnsRecords: key.dkim_dns_records,
|
|
121
|
-
domain: key.domain,
|
|
122
|
-
gracePeriodExpiresAt: key.gracePeriodExpiresAt,
|
|
123
|
-
length: key.key_length,
|
|
124
|
-
publicKey: key.public_key,
|
|
125
|
-
retiresAt: key.retiresAt,
|
|
126
|
-
selector: key.selector,
|
|
127
|
-
status: key.status,
|
|
128
|
-
statusModifiedAt: key.status_modified_at
|
|
129
|
-
});
|
|
130
119
|
const isValidEmail = (email) => {
|
|
131
120
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
132
121
|
};
|
|
@@ -157,6 +146,7 @@ const parseArrayRecipients = (recipients) => {
|
|
|
157
146
|
const filtered = (typeof recipients === "string" ? [parseRecipientString(recipients)] : Array.isArray(recipients) ? recipients.map(parseRecipient) : [recipients]).filter((recipient) => Boolean(recipient));
|
|
158
147
|
return filtered.length > 0 ? filtered : void 0;
|
|
159
148
|
};
|
|
149
|
+
const stripPemHeaders = (pem) => pem.replace(/-----[^-]+-----|\s|#.*$/gm, "");
|
|
160
150
|
const RESERVED_HEADER_NAMES = new Set([
|
|
161
151
|
"authentication-results",
|
|
162
152
|
"bcc",
|
|
@@ -207,6 +197,13 @@ const mapDkim = (dkim) => ({
|
|
|
207
197
|
dkim_private_key: dkim?.privateKey ? stripPemHeaders(dkim.privateKey) : void 0,
|
|
208
198
|
dkim_selector: dkim?.selector
|
|
209
199
|
});
|
|
200
|
+
const mapAttachment = (attachment) => ({
|
|
201
|
+
content: attachment.content,
|
|
202
|
+
filename: attachment.filename,
|
|
203
|
+
type: attachment.type,
|
|
204
|
+
content_id: attachment.contentId,
|
|
205
|
+
disposition: attachment.disposition
|
|
206
|
+
});
|
|
210
207
|
const mapPersonalization = (personalization, index, rootTemplateData) => {
|
|
211
208
|
const to = parseArrayRecipients(personalization.to);
|
|
212
209
|
if (!to || !to.length) return `Personalization at index ${index} must include at least one recipient in the 'to' field.`;
|
|
@@ -238,7 +235,11 @@ const mapPersonalization = (personalization, index, rootTemplateData) => {
|
|
|
238
235
|
to
|
|
239
236
|
};
|
|
240
237
|
};
|
|
241
|
-
const
|
|
238
|
+
const resolveAttachments = async (attachments) => {
|
|
239
|
+
if (!attachments) return;
|
|
240
|
+
return Promise.all(attachments.map((a) => Promise.resolve(a))).catch((e) => e.message);
|
|
241
|
+
};
|
|
242
|
+
const buildSendPayload = async (options) => {
|
|
242
243
|
const { from, html, text } = options;
|
|
243
244
|
const contentTypes = options.content ? new Set(options.content.map((item) => item.type.toLowerCase())) : void 0;
|
|
244
245
|
const parsedFrom = parseRecipient(from);
|
|
@@ -307,8 +308,10 @@ const buildSendPayload = (options) => {
|
|
|
307
308
|
value: item.value,
|
|
308
309
|
template_type
|
|
309
310
|
});
|
|
311
|
+
const resolvedAttachments = await resolveAttachments(options.attachments);
|
|
312
|
+
if (typeof resolvedAttachments === "string") return resolvedAttachments;
|
|
310
313
|
return {
|
|
311
|
-
attachments:
|
|
314
|
+
attachments: resolvedAttachments?.map((a) => mapAttachment(a)),
|
|
312
315
|
campaign_id: options.campaignId,
|
|
313
316
|
...mapDkim(options.dkim),
|
|
314
317
|
envelope_from: parseRecipient(options.envelopeFrom),
|
|
@@ -332,7 +335,7 @@ var Emails = class {
|
|
|
332
335
|
}
|
|
333
336
|
async _sendEmail(options, flags) {
|
|
334
337
|
let error = null;
|
|
335
|
-
const payload = buildSendPayload(options);
|
|
338
|
+
const payload = await buildSendPayload(options);
|
|
336
339
|
if (typeof payload === "string") {
|
|
337
340
|
error = createError(payload);
|
|
338
341
|
return {
|
|
@@ -387,10 +390,26 @@ var Emails = class {
|
|
|
387
390
|
async send(options, dryRun = false) {
|
|
388
391
|
return this._sendEmail(options, { dryRun });
|
|
389
392
|
}
|
|
390
|
-
async
|
|
393
|
+
async queue(options) {
|
|
391
394
|
return this._sendEmail(options, { async: true });
|
|
392
395
|
}
|
|
396
|
+
async sendAsync(options) {
|
|
397
|
+
return this.queue(options);
|
|
398
|
+
}
|
|
393
399
|
};
|
|
400
|
+
const mapDkimKey = (key) => ({
|
|
401
|
+
algorithm: key.algorithm,
|
|
402
|
+
createdAt: key.created_at,
|
|
403
|
+
dnsRecords: key.dkim_dns_records,
|
|
404
|
+
domain: key.domain,
|
|
405
|
+
gracePeriodExpiresAt: key.gracePeriodExpiresAt,
|
|
406
|
+
length: key.key_length,
|
|
407
|
+
publicKey: key.public_key,
|
|
408
|
+
retiresAt: key.retiresAt,
|
|
409
|
+
selector: key.selector,
|
|
410
|
+
status: key.status,
|
|
411
|
+
statusModifiedAt: key.status_modified_at
|
|
412
|
+
});
|
|
394
413
|
var Domains = class {
|
|
395
414
|
mailchannels;
|
|
396
415
|
dkim;
|
|
@@ -398,10 +417,16 @@ var Domains = class {
|
|
|
398
417
|
this.mailchannels = mailchannels;
|
|
399
418
|
this.dkim = new DomainsDkim(mailchannels);
|
|
400
419
|
}
|
|
401
|
-
async check(options) {
|
|
420
|
+
async check(domain, options) {
|
|
402
421
|
let error = null;
|
|
403
|
-
|
|
404
|
-
|
|
422
|
+
if (!domain) {
|
|
423
|
+
error = createError("No domain provided.");
|
|
424
|
+
return {
|
|
425
|
+
data: null,
|
|
426
|
+
error
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const dkimOptions = options?.dkim ? Array.isArray(options.dkim) ? options.dkim : [options.dkim] : void 0;
|
|
405
430
|
if (dkimOptions && dkimOptions.length > 10) {
|
|
406
431
|
error = createError("A maximum of 10 DKIM settings can be provided.");
|
|
407
432
|
return {
|
|
@@ -417,13 +442,13 @@ var Domains = class {
|
|
|
417
442
|
};
|
|
418
443
|
}
|
|
419
444
|
const payload = {
|
|
420
|
-
dkim_settings: dkimOptions?.map((
|
|
421
|
-
dkim_domain: domain,
|
|
422
|
-
dkim_private_key: privateKey ? stripPemHeaders(privateKey) : void 0,
|
|
423
|
-
dkim_selector: selector
|
|
445
|
+
dkim_settings: dkimOptions?.map((dkim) => ({
|
|
446
|
+
dkim_domain: dkim.domain,
|
|
447
|
+
dkim_private_key: dkim.privateKey ? stripPemHeaders(dkim.privateKey) : void 0,
|
|
448
|
+
dkim_selector: dkim.selector
|
|
424
449
|
})),
|
|
425
450
|
domain,
|
|
426
|
-
sender_id: senderId
|
|
451
|
+
sender_id: options?.senderId
|
|
427
452
|
};
|
|
428
453
|
const response = await this.mailchannels.post("/tx/v1/check-domain", {
|
|
429
454
|
body: payload,
|
|
@@ -466,6 +491,13 @@ var DomainsDkim = class {
|
|
|
466
491
|
}
|
|
467
492
|
async create(domain, options) {
|
|
468
493
|
let error = null;
|
|
494
|
+
if (!domain) {
|
|
495
|
+
error = createError("No domain provided.");
|
|
496
|
+
return {
|
|
497
|
+
data: null,
|
|
498
|
+
error
|
|
499
|
+
};
|
|
500
|
+
}
|
|
469
501
|
if (!options.selector || options.selector.length > 63) {
|
|
470
502
|
error = createError("Selector must be between 1 and 63 characters.");
|
|
471
503
|
return {
|
|
@@ -501,6 +533,13 @@ var DomainsDkim = class {
|
|
|
501
533
|
}
|
|
502
534
|
async list(domain, options) {
|
|
503
535
|
let error = null;
|
|
536
|
+
if (!domain) {
|
|
537
|
+
error = createError("No domain provided.");
|
|
538
|
+
return {
|
|
539
|
+
data: null,
|
|
540
|
+
error
|
|
541
|
+
};
|
|
542
|
+
}
|
|
504
543
|
if (options?.selector && options.selector.length > 63) {
|
|
505
544
|
error = createError("Selector must be between 1 and 63 characters.");
|
|
506
545
|
return {
|
|
@@ -541,8 +580,15 @@ var DomainsDkim = class {
|
|
|
541
580
|
error: null
|
|
542
581
|
};
|
|
543
582
|
}
|
|
544
|
-
async
|
|
583
|
+
async updateStatus(domain, options) {
|
|
545
584
|
let error = null;
|
|
585
|
+
if (!domain) {
|
|
586
|
+
error = createError("No domain provided.");
|
|
587
|
+
return {
|
|
588
|
+
success: false,
|
|
589
|
+
error
|
|
590
|
+
};
|
|
591
|
+
}
|
|
546
592
|
if (!options.selector || options.selector.length > 63) {
|
|
547
593
|
error = createError("Selector must be between 1 and 63 characters.");
|
|
548
594
|
return {
|
|
@@ -560,7 +606,7 @@ var DomainsDkim = class {
|
|
|
560
606
|
});
|
|
561
607
|
}
|
|
562
608
|
}).catch((e) => {
|
|
563
|
-
error ||= getResultError(e, "Failed to update DKIM key.");
|
|
609
|
+
error ||= getResultError(e, "Failed to update status of DKIM key.");
|
|
564
610
|
});
|
|
565
611
|
return {
|
|
566
612
|
success: !error,
|
|
@@ -569,6 +615,13 @@ var DomainsDkim = class {
|
|
|
569
615
|
}
|
|
570
616
|
async rotate(domain, selector, options) {
|
|
571
617
|
let error = null;
|
|
618
|
+
if (!domain) {
|
|
619
|
+
error = createError("No domain provided.");
|
|
620
|
+
return {
|
|
621
|
+
data: null,
|
|
622
|
+
error
|
|
623
|
+
};
|
|
624
|
+
}
|
|
572
625
|
if (!selector || selector.length > 63) {
|
|
573
626
|
error = createError("Selector must be between 1 and 63 characters.");
|
|
574
627
|
return {
|
|
@@ -687,7 +740,7 @@ var Webhooks = class Webhooks {
|
|
|
687
740
|
constructor(mailchannels) {
|
|
688
741
|
this.mailchannels = mailchannels;
|
|
689
742
|
}
|
|
690
|
-
async
|
|
743
|
+
async create(endpoint) {
|
|
691
744
|
let error = null;
|
|
692
745
|
if (!endpoint) {
|
|
693
746
|
error = createError("No endpoint provided.");
|
|
@@ -709,7 +762,7 @@ var Webhooks = class Webhooks {
|
|
|
709
762
|
error = getStatusError(response, { [409]: `Endpoint '${endpoint}' is already enrolled to receive notifications.` });
|
|
710
763
|
}
|
|
711
764
|
}).catch((e) => {
|
|
712
|
-
error ||= getResultError(e, "Failed to
|
|
765
|
+
error ||= getResultError(e, "Failed to create webhook.");
|
|
713
766
|
});
|
|
714
767
|
return {
|
|
715
768
|
success: !error,
|
|
@@ -733,7 +786,7 @@ var Webhooks = class Webhooks {
|
|
|
733
786
|
error: null
|
|
734
787
|
};
|
|
735
788
|
}
|
|
736
|
-
async
|
|
789
|
+
async deleteAll() {
|
|
737
790
|
let error = null;
|
|
738
791
|
await this.mailchannels.delete("/tx/v1/webhook", { onResponseError: async ({ response }) => {
|
|
739
792
|
error = getStatusError(response);
|
|
@@ -805,7 +858,48 @@ var Webhooks = class Webhooks {
|
|
|
805
858
|
};
|
|
806
859
|
}
|
|
807
860
|
static async verify(options) {
|
|
808
|
-
|
|
861
|
+
let error = null;
|
|
862
|
+
if (!await isValidWebhook(options).catch(() => false)) {
|
|
863
|
+
error = createError("Invalid webhook signature.");
|
|
864
|
+
return {
|
|
865
|
+
data: null,
|
|
866
|
+
error
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
try {
|
|
870
|
+
const payload = JSON.parse(options.payload);
|
|
871
|
+
if (!Array.isArray(payload)) {
|
|
872
|
+
error = createError("Invalid webhook payload.");
|
|
873
|
+
return {
|
|
874
|
+
data: null,
|
|
875
|
+
error
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
return {
|
|
879
|
+
data: clean(payload.map((event) => ({
|
|
880
|
+
email: event.email,
|
|
881
|
+
customerHandle: event.customer_handle,
|
|
882
|
+
timestamp: event.timestamp,
|
|
883
|
+
smtpId: event.smtp_id,
|
|
884
|
+
event: event.event,
|
|
885
|
+
requestId: event.request_id,
|
|
886
|
+
campaignId: "campaign_id" in event ? event.campaign_id : void 0,
|
|
887
|
+
recipients: "recipients" in event ? event.recipients : void 0,
|
|
888
|
+
userAgent: "user_agent" in event ? event.user_agent : void 0,
|
|
889
|
+
ip: "ip" in event ? event.ip : void 0,
|
|
890
|
+
url: "url" in event ? event.url : void 0,
|
|
891
|
+
status: "status" in event ? event.status : void 0,
|
|
892
|
+
reason: "reason" in event ? event.reason : void 0
|
|
893
|
+
}))),
|
|
894
|
+
error: null
|
|
895
|
+
};
|
|
896
|
+
} catch {
|
|
897
|
+
error = createError("Invalid webhook payload.");
|
|
898
|
+
return {
|
|
899
|
+
data: null,
|
|
900
|
+
error
|
|
901
|
+
};
|
|
902
|
+
}
|
|
809
903
|
}
|
|
810
904
|
async verify(options) {
|
|
811
905
|
return Webhooks.verify(options);
|
|
@@ -1322,6 +1416,12 @@ var SubAccounts = class SubAccounts {
|
|
|
1322
1416
|
};
|
|
1323
1417
|
}
|
|
1324
1418
|
};
|
|
1419
|
+
const mapBucket = (bucket) => {
|
|
1420
|
+
return {
|
|
1421
|
+
count: bucket.count,
|
|
1422
|
+
periodStart: bucket.period_start
|
|
1423
|
+
};
|
|
1424
|
+
};
|
|
1325
1425
|
var Metrics = class {
|
|
1326
1426
|
mailchannels;
|
|
1327
1427
|
constructor(mailchannels) {
|
|
@@ -1350,10 +1450,10 @@ var Metrics = class {
|
|
|
1350
1450
|
return {
|
|
1351
1451
|
data: clean({
|
|
1352
1452
|
buckets: {
|
|
1353
|
-
click:
|
|
1354
|
-
clickTrackingDelivered:
|
|
1355
|
-
open:
|
|
1356
|
-
openTrackingDelivered:
|
|
1453
|
+
click: response.buckets.click.map(mapBucket),
|
|
1454
|
+
clickTrackingDelivered: response.buckets.click_tracking_delivered.map(mapBucket),
|
|
1455
|
+
open: response.buckets.open.map(mapBucket),
|
|
1456
|
+
openTrackingDelivered: response.buckets.open_tracking_delivered.map(mapBucket)
|
|
1357
1457
|
},
|
|
1358
1458
|
click: response.click,
|
|
1359
1459
|
clickTrackingDelivered: response.click_tracking_delivered,
|
|
@@ -1389,9 +1489,9 @@ var Metrics = class {
|
|
|
1389
1489
|
data: clean({
|
|
1390
1490
|
bounced: response.bounced,
|
|
1391
1491
|
buckets: {
|
|
1392
|
-
bounced:
|
|
1393
|
-
delivered:
|
|
1394
|
-
processed:
|
|
1492
|
+
bounced: response.buckets.bounced.map(mapBucket),
|
|
1493
|
+
delivered: response.buckets.delivered.map(mapBucket),
|
|
1494
|
+
processed: response.buckets.processed.map(mapBucket)
|
|
1395
1495
|
},
|
|
1396
1496
|
delivered: response.delivered,
|
|
1397
1497
|
endTime: response.end_time,
|
|
@@ -1424,8 +1524,8 @@ var Metrics = class {
|
|
|
1424
1524
|
return {
|
|
1425
1525
|
data: clean({
|
|
1426
1526
|
buckets: {
|
|
1427
|
-
unsubscribeDelivered:
|
|
1428
|
-
unsubscribed:
|
|
1527
|
+
unsubscribeDelivered: response.buckets.unsubscribe_delivered.map(mapBucket),
|
|
1528
|
+
unsubscribed: response.buckets.unsubscribed.map(mapBucket)
|
|
1429
1529
|
},
|
|
1430
1530
|
endTime: response.end_time,
|
|
1431
1531
|
startTime: response.start_time,
|
|
@@ -1458,9 +1558,9 @@ var Metrics = class {
|
|
|
1458
1558
|
return {
|
|
1459
1559
|
data: clean({
|
|
1460
1560
|
buckets: {
|
|
1461
|
-
delivered:
|
|
1462
|
-
dropped:
|
|
1463
|
-
processed:
|
|
1561
|
+
delivered: response.buckets.delivered.map(mapBucket),
|
|
1562
|
+
dropped: response.buckets.dropped.map(mapBucket),
|
|
1563
|
+
processed: response.buckets.processed.map(mapBucket)
|
|
1464
1564
|
},
|
|
1465
1565
|
delivered: response.delivered,
|
|
1466
1566
|
dropped: response.dropped,
|
|
@@ -1640,6 +1740,62 @@ var Suppressions = class {
|
|
|
1640
1740
|
};
|
|
1641
1741
|
}
|
|
1642
1742
|
};
|
|
1743
|
+
const base64Content = (data) => {
|
|
1744
|
+
if (data instanceof ArrayBuffer) return Buffer.from(data).toString("base64");
|
|
1745
|
+
return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64");
|
|
1746
|
+
};
|
|
1747
|
+
const guessContentType = (filename) => {
|
|
1748
|
+
return mime.getType(filename) || void 0;
|
|
1749
|
+
};
|
|
1750
|
+
var Attachment = class Attachment {
|
|
1751
|
+
static fromBytes(data, options) {
|
|
1752
|
+
const { filename, type, contentId, disposition = "attachment" } = options;
|
|
1753
|
+
return {
|
|
1754
|
+
content: base64Content(data),
|
|
1755
|
+
filename: decodeURIComponent(filename) || "attachment",
|
|
1756
|
+
type: type || guessContentType(filename),
|
|
1757
|
+
contentId,
|
|
1758
|
+
disposition
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
static async fromFile(path, options) {
|
|
1762
|
+
try {
|
|
1763
|
+
const data = await readFile(path);
|
|
1764
|
+
return Attachment.fromBytes(data, {
|
|
1765
|
+
filename: basename(path.toString()),
|
|
1766
|
+
...options
|
|
1767
|
+
});
|
|
1768
|
+
} catch (error) {
|
|
1769
|
+
throw new Error(`Unable to read attachment file: ${path}`, { cause: error });
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
static async fromUrl(url, options) {
|
|
1773
|
+
try {
|
|
1774
|
+
let contentType;
|
|
1775
|
+
const data = await $fetch(url, {
|
|
1776
|
+
responseType: "arrayBuffer",
|
|
1777
|
+
timeout: 12e4,
|
|
1778
|
+
onResponse: ({ response }) => {
|
|
1779
|
+
const contentTypeHeader = response.headers.get("content-type");
|
|
1780
|
+
if (contentTypeHeader) contentType = contentTypeHeader.split(";", 1)[0]?.trim();
|
|
1781
|
+
}
|
|
1782
|
+
});
|
|
1783
|
+
return Attachment.fromBytes(data, {
|
|
1784
|
+
type: contentType,
|
|
1785
|
+
filename: basename(new URL(url).pathname),
|
|
1786
|
+
...options
|
|
1787
|
+
});
|
|
1788
|
+
} catch (error) {
|
|
1789
|
+
throw new Error(`Unable to fetch attachment from URL: ${url}`, { cause: error });
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
static inlineFile(path, options) {
|
|
1793
|
+
return Attachment.fromFile(path, {
|
|
1794
|
+
...options,
|
|
1795
|
+
disposition: "inline"
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1643
1799
|
var MailChannels = class extends MailChannelsClient {
|
|
1644
1800
|
emails = new Emails(this);
|
|
1645
1801
|
domains = new Domains(this);
|
|
@@ -1651,4 +1807,4 @@ var MailChannels = class extends MailChannelsClient {
|
|
|
1651
1807
|
super(key, options);
|
|
1652
1808
|
}
|
|
1653
1809
|
};
|
|
1654
|
-
export { Domains, Emails, MailChannels, MailChannelsClient, Metrics, SubAccounts, Suppressions, Webhooks };
|
|
1810
|
+
export { Attachment, Domains, Emails, MailChannels, MailChannelsClient, Metrics, SubAccounts, Suppressions, Webhooks };
|
package/package.json
CHANGED
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mailchannels-sdk",
|
|
3
|
-
"version": "0.8.0
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Node.js SDK to integrate MailChannels Email API into your JavaScript or TypeScript server-side applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"mailchannels",
|
|
9
|
-
"javascript",
|
|
10
9
|
"typescript",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
10
|
+
"email",
|
|
11
|
+
"transactional-email",
|
|
12
|
+
"sdk"
|
|
14
13
|
],
|
|
15
14
|
"repository": {
|
|
16
15
|
"type": "git",
|
|
17
|
-
"url": "git+https://
|
|
16
|
+
"url": "git+https://bitbucket.org/mailchannels/mailchannels-email-api-sdk-js.git"
|
|
18
17
|
},
|
|
19
18
|
"homepage": "https://mailchannels.yizack.com",
|
|
20
19
|
"author": {
|
|
21
|
-
"name": "
|
|
22
|
-
"email": "
|
|
23
|
-
"url": "https://yizack.com"
|
|
20
|
+
"name": "MailChannels",
|
|
21
|
+
"email": "dev@mailchannels.com"
|
|
24
22
|
},
|
|
25
23
|
"main": "./dist/mailchannels.mjs",
|
|
26
24
|
"exports": {
|
|
@@ -38,22 +36,26 @@
|
|
|
38
36
|
"dist"
|
|
39
37
|
],
|
|
40
38
|
"dependencies": {
|
|
39
|
+
"mime": "^4.1.0",
|
|
41
40
|
"ofetch": "^2.0.0-alpha.3"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
45
44
|
"@types/markdown-it": "^14.1.2",
|
|
46
|
-
"@types/node": "^25.
|
|
47
|
-
"@vitest/coverage-v8": "^4.1.
|
|
45
|
+
"@types/node": "^25.9.1",
|
|
46
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
48
47
|
"changelogen": "^0.6.2",
|
|
49
|
-
"obuild": "^0.4.
|
|
50
|
-
"oxlint": "^1.
|
|
48
|
+
"obuild": "^0.4.36",
|
|
49
|
+
"oxlint": "^1.67.0",
|
|
51
50
|
"scule": "^1.3.0",
|
|
52
51
|
"typescript": "^6.0.3",
|
|
53
52
|
"vitepress": "^2.0.0-alpha.17",
|
|
54
53
|
"vitepress-plugin-group-icons": "^1.7.5",
|
|
55
|
-
"vitepress-plugin-llms": "^1.
|
|
56
|
-
"vitest": "^4.1.
|
|
54
|
+
"vitepress-plugin-llms": "^1.13.0",
|
|
55
|
+
"vitest": "^4.1.7"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20"
|
|
57
59
|
},
|
|
58
60
|
"scripts": {
|
|
59
61
|
"build": "obuild",
|