ts-mailkit 2.1.0 → 3.1.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 +6 -2
- package/dist/core/client.d.ts +7 -43
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/types.d.ts +126 -10
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.cjs +82 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -50
- package/dist/index.js.map +1 -1
- package/dist/renderers/default/default-renderer.d.ts +5 -22
- package/dist/renderers/default/default-renderer.d.ts.map +1 -1
- package/dist/renderers/renderer.interface.d.ts +25 -0
- package/dist/renderers/renderer.interface.d.ts.map +1 -1
- package/dist/templates/dto/index.d.ts +13 -24
- package/dist/templates/dto/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +1 -0
- package/dist/templates/factory.d.ts.map +1 -1
- package/dist/templates/template-builder.d.ts +2 -19
- package/dist/templates/template-builder.d.ts.map +1 -1
- package/dist/transports/console/console-sender.d.ts +1 -1
- package/dist/transports/console/console-sender.d.ts.map +1 -1
- package/dist/transports/cpaas/cpaas-sender.d.ts +10 -2
- package/dist/transports/cpaas/cpaas-sender.d.ts.map +1 -1
- package/dist/transports/memory/memory-sender.d.ts +1 -1
- package/dist/transports/memory/memory-sender.d.ts.map +1 -1
- package/dist/transports/sender.interface.d.ts +1 -1
- package/dist/transports/sender.interface.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/core/bulk-types.d.ts +0 -196
- package/dist/core/bulk-types.d.ts.map +0 -1
- package/dist/transports/zeptomail/types.d.ts +0 -6
- package/dist/transports/zeptomail/types.d.ts.map +0 -1
- package/dist/transports/zeptomail/zeptomail-sender.d.ts +0 -7
- package/dist/transports/zeptomail/zeptomail-sender.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -258,17 +258,12 @@ var MailKit = class {
|
|
|
258
258
|
});
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
|
-
*
|
|
262
|
-
*/
|
|
263
|
-
async send(options) {
|
|
264
|
-
return await this.sendMail(options);
|
|
265
|
-
}
|
|
266
|
-
/**
|
|
267
|
-
* Sends a bulk email using a strongly-typed template DTO.
|
|
261
|
+
* Sends the same rendered template DTO to every recipient in a single batch.
|
|
268
262
|
*
|
|
269
263
|
* The transport delivers an individual copy to each recipient, so
|
|
270
|
-
* recipients are not exposed to one another.
|
|
271
|
-
*
|
|
264
|
+
* recipients are not exposed to one another. The content is identical for
|
|
265
|
+
* everyone; for per-recipient content, use {@link sendBulkKnownTemplate}
|
|
266
|
+
* with a provider-side template and `mergeInfo`.
|
|
272
267
|
*
|
|
273
268
|
* Example:
|
|
274
269
|
* ```ts
|
|
@@ -300,7 +295,9 @@ var MailKit = class {
|
|
|
300
295
|
tags: options.tags,
|
|
301
296
|
metadata: options.metadata,
|
|
302
297
|
trackClicks: options.trackClicks,
|
|
303
|
-
trackOpens: options.trackOpens
|
|
298
|
+
trackOpens: options.trackOpens,
|
|
299
|
+
bounceAddress: options.bounceAddress,
|
|
300
|
+
clientReference: options.clientReference
|
|
304
301
|
});
|
|
305
302
|
}
|
|
306
303
|
/**
|
|
@@ -363,7 +360,12 @@ function createMailKit(options) {
|
|
|
363
360
|
//#endregion
|
|
364
361
|
//#region src/transports/cpaas/cpaas-sender.ts
|
|
365
362
|
/**
|
|
366
|
-
* Zoho CPaaS
|
|
363
|
+
* Zoho CPaaS accepts at most 500 recipients per request, counted across
|
|
364
|
+
* `to`, `cc`, and `bcc`.
|
|
365
|
+
*/
|
|
366
|
+
const CPAAS_MAX_RECIPIENTS = 500;
|
|
367
|
+
/**
|
|
368
|
+
* Zoho CPaaS transactional email HTTP transport adapter.
|
|
367
369
|
*
|
|
368
370
|
* Uses the standard global `fetch` API for zero-dependency, universal edge
|
|
369
371
|
* compatibility (Node.js, Bun, Deno, Cloudflare Workers).
|
|
@@ -373,6 +375,9 @@ function createMailKit(options) {
|
|
|
373
375
|
* - `sendBulk` — batch raw email (`POST /v1.1/email/batch`)
|
|
374
376
|
* - `sendKnownTemplate` — single template email (`POST /v1.1/email/template`)
|
|
375
377
|
* - `sendBulkKnownTemplate` — batch template email (`POST /v1.1/email/template/batch`)
|
|
378
|
+
*
|
|
379
|
+
* Requests exceeding Zoho's 500-recipient limit (across `to`, `cc`, and `bcc`)
|
|
380
|
+
* are rejected before any network call is made.
|
|
376
381
|
*/
|
|
377
382
|
var CpaasHttpSender = class {
|
|
378
383
|
name = "cpaas";
|
|
@@ -425,7 +430,16 @@ var CpaasHttpSender = class {
|
|
|
425
430
|
const payload = this.buildBatchTemplatePayload(options);
|
|
426
431
|
return await this.post(`${this.apiBase}/email/template/batch`, payload);
|
|
427
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Guards against requests that exceed Zoho CPaaS's per-request recipient
|
|
435
|
+
* limit, counted across `to`, `cc`, and `bcc`.
|
|
436
|
+
*/
|
|
437
|
+
assertRecipientLimit(to, cc, bcc) {
|
|
438
|
+
const total = normalizeRecipients(to).length + normalizeRecipients(cc).length + normalizeRecipients(bcc).length;
|
|
439
|
+
if (total > CPAAS_MAX_RECIPIENTS) throw new TransportError(`CpaasHttpSender: Too many recipients (${total}). Zoho CPaaS accepts at most ${CPAAS_MAX_RECIPIENTS} recipients per request across to, cc, and bcc.`, { transportName: this.name });
|
|
440
|
+
}
|
|
428
441
|
buildSendPayload(options) {
|
|
442
|
+
this.assertRecipientLimit(options.to, options.cc, options.bcc);
|
|
429
443
|
const toRecipients = normalizeRecipients(options.to);
|
|
430
444
|
if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
|
|
431
445
|
const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
|
|
@@ -446,6 +460,7 @@ var CpaasHttpSender = class {
|
|
|
446
460
|
return payload;
|
|
447
461
|
}
|
|
448
462
|
buildTemplatePayload(options) {
|
|
463
|
+
this.assertRecipientLimit(options.to, options.cc, options.bcc);
|
|
449
464
|
const toRecipients = normalizeRecipients(options.to);
|
|
450
465
|
if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
|
|
451
466
|
const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
|
|
@@ -465,6 +480,7 @@ var CpaasHttpSender = class {
|
|
|
465
480
|
return payload;
|
|
466
481
|
}
|
|
467
482
|
buildBatchTemplatePayload(options) {
|
|
483
|
+
this.assertRecipientLimit(options.to, options.cc, options.bcc);
|
|
468
484
|
if (!options.to || options.to.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
|
|
469
485
|
const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
|
|
470
486
|
const payload = {
|
|
@@ -569,8 +585,7 @@ var CpaasHttpSender = class {
|
|
|
569
585
|
return {
|
|
570
586
|
success: true,
|
|
571
587
|
messageId: responseData?.data?.[0]?.message_id,
|
|
572
|
-
rawResponse: responseData
|
|
573
|
-
response: responseData
|
|
588
|
+
rawResponse: responseData
|
|
574
589
|
};
|
|
575
590
|
}
|
|
576
591
|
};
|
|
@@ -591,12 +606,10 @@ var MemoryEmailSender = class {
|
|
|
591
606
|
result(prefix) {
|
|
592
607
|
const id = this.nextId++;
|
|
593
608
|
const messageId = prefix ? `mem-${prefix}-${id}-${Date.now()}` : `mem-${id}-${Date.now()}`;
|
|
594
|
-
const rawResponse = { id: messageId };
|
|
595
609
|
return {
|
|
596
610
|
success: true,
|
|
597
611
|
messageId,
|
|
598
|
-
rawResponse
|
|
599
|
-
response: rawResponse
|
|
612
|
+
rawResponse: { id: messageId }
|
|
600
613
|
};
|
|
601
614
|
}
|
|
602
615
|
async send(options) {
|
|
@@ -738,12 +751,10 @@ var ConsoleEmailSender = class {
|
|
|
738
751
|
}
|
|
739
752
|
lines.push(`└${separator}┘\n`);
|
|
740
753
|
this.log(lines.join("\n"));
|
|
741
|
-
const rawResponse = { logged: true };
|
|
742
754
|
return {
|
|
743
755
|
success: true,
|
|
744
756
|
messageId,
|
|
745
|
-
rawResponse
|
|
746
|
-
response: rawResponse
|
|
757
|
+
rawResponse: { logged: true }
|
|
747
758
|
};
|
|
748
759
|
}
|
|
749
760
|
};
|
|
@@ -778,130 +789,152 @@ var EmailTemplateFactory = class EmailTemplateFactory {
|
|
|
778
789
|
buildFooter(brandName) {
|
|
779
790
|
return this.footerResolver(brandName);
|
|
780
791
|
}
|
|
792
|
+
arrangePlainTextWithExtras(base, extraMessage, footer) {
|
|
793
|
+
const parts = [base];
|
|
794
|
+
if (extraMessage) parts.push(htmlToPlainText(extraMessage));
|
|
795
|
+
if (footer) parts.push(htmlToPlainText(footer));
|
|
796
|
+
return parts.join("\n\n");
|
|
797
|
+
}
|
|
781
798
|
/**
|
|
782
799
|
* Welcome / email-verification email sent after registration.
|
|
783
800
|
*/
|
|
784
801
|
createEmailVerification(params) {
|
|
785
|
-
const { username, verificationUrl, otp, brandName } = params;
|
|
802
|
+
const { username, verificationUrl, otp, brandName, logoUrl, extraMessage, footer } = params;
|
|
786
803
|
const brand = this.resolveBrand(brandName);
|
|
787
804
|
const body = `Hi ${username},<br/>Thank you for signing up. Use the code below or click the button to verify your email address.`;
|
|
805
|
+
const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
|
|
806
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
807
|
+
const plainTextBody = htmlToPlainText(body) + `\n\nYour verification code is: ${otp}\n\nAlternatively, verify here:\n${verificationUrl}`;
|
|
788
808
|
return {
|
|
789
809
|
subject: "Verify Your Email Address",
|
|
790
810
|
header: `Welcome to ${brand}!`,
|
|
791
811
|
body,
|
|
792
|
-
logoUrl: this.defaultLogoUrl,
|
|
812
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
793
813
|
otpCode: otp,
|
|
794
814
|
actionUrl: verificationUrl,
|
|
795
815
|
actionText: "Verify Email",
|
|
796
|
-
extraMessage:
|
|
797
|
-
footer:
|
|
816
|
+
extraMessage: resolvedExtraMessage,
|
|
817
|
+
footer: resolvedFooter,
|
|
798
818
|
userName: username,
|
|
799
819
|
fromName: brand,
|
|
800
|
-
noHtmlMessage:
|
|
820
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
|
|
801
821
|
};
|
|
802
822
|
}
|
|
803
823
|
/**
|
|
804
824
|
* Password-reset email with an optional OTP code and action link.
|
|
805
825
|
*/
|
|
806
826
|
createPasswordReset(params) {
|
|
807
|
-
const { username, resetUrl, otp = "", brandName } = params;
|
|
827
|
+
const { username, resetUrl, otp = "", brandName, logoUrl, extraMessage, footer } = params;
|
|
808
828
|
const brand = this.resolveBrand(brandName);
|
|
809
829
|
const body = `Hi ${username},<br/>We received a request to reset your password. Use the OTP code below or click the button to proceed.`;
|
|
810
830
|
const plainTextOtp = otp ? `\n\nYour OTP code is: ${otp}` : "";
|
|
831
|
+
const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
|
|
832
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
833
|
+
const plainTextBody = htmlToPlainText(body) + plainTextOtp + `\n\nAlternatively, you can use the following link to reset your password:\n${resetUrl}`;
|
|
811
834
|
return {
|
|
812
835
|
subject: "Password Reset Request",
|
|
813
836
|
header: "Reset Your Password",
|
|
814
837
|
body,
|
|
815
|
-
logoUrl: this.defaultLogoUrl,
|
|
838
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
816
839
|
otpCode: otp || void 0,
|
|
817
840
|
actionUrl: resetUrl,
|
|
818
841
|
actionText: "Reset Password",
|
|
819
|
-
extraMessage:
|
|
820
|
-
footer:
|
|
842
|
+
extraMessage: resolvedExtraMessage,
|
|
843
|
+
footer: resolvedFooter,
|
|
821
844
|
userName: username,
|
|
822
845
|
fromName: brand,
|
|
823
|
-
noHtmlMessage:
|
|
846
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
|
|
824
847
|
};
|
|
825
848
|
}
|
|
826
849
|
/**
|
|
827
850
|
* Generic plain message email (no action button, no OTP).
|
|
828
851
|
*/
|
|
829
852
|
createSimpleMessage(params) {
|
|
830
|
-
const { subject, header, body, brandName } = params;
|
|
853
|
+
const { subject, header, body, brandName, logoUrl, extraMessage, footer } = params;
|
|
831
854
|
const brand = this.resolveBrand(brandName);
|
|
855
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
832
856
|
return {
|
|
833
857
|
subject,
|
|
834
858
|
header,
|
|
835
859
|
body,
|
|
836
|
-
logoUrl: this.defaultLogoUrl,
|
|
837
|
-
|
|
860
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
861
|
+
extraMessage,
|
|
862
|
+
footer: resolvedFooter,
|
|
838
863
|
fromName: brand,
|
|
839
|
-
noHtmlMessage: htmlToPlainText(body)
|
|
864
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(htmlToPlainText(body), extraMessage, resolvedFooter)
|
|
840
865
|
};
|
|
841
866
|
}
|
|
842
867
|
/**
|
|
843
868
|
* Newsletter / announcement email with an optional hero image and CTA button.
|
|
844
869
|
*/
|
|
845
870
|
createNewsLetter(params) {
|
|
846
|
-
const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl } = params;
|
|
871
|
+
const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl, extraMessage, footer } = params;
|
|
847
872
|
const brand = this.resolveBrand(brandName);
|
|
848
|
-
|
|
849
|
-
|
|
873
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
874
|
+
let plainTextBody = htmlToPlainText(body);
|
|
875
|
+
if (actionUrl) plainTextBody += `\n\n${actionText || "Learn more"}: ${actionUrl}`;
|
|
850
876
|
return {
|
|
851
877
|
subject,
|
|
852
878
|
header,
|
|
853
879
|
body,
|
|
854
|
-
logoUrl: logoUrl
|
|
880
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
855
881
|
imageUrl,
|
|
856
882
|
actionUrl,
|
|
857
883
|
actionText,
|
|
858
|
-
|
|
884
|
+
extraMessage,
|
|
885
|
+
footer: resolvedFooter,
|
|
859
886
|
fromName: brand,
|
|
860
|
-
noHtmlMessage
|
|
887
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, extraMessage, resolvedFooter)
|
|
861
888
|
};
|
|
862
889
|
}
|
|
863
890
|
/**
|
|
864
891
|
* Two-factor authentication email with OTP code and optional magic link.
|
|
865
892
|
*/
|
|
866
893
|
create2FAEmail(params) {
|
|
867
|
-
const { username, otp, magicLink = "", brandName } = params;
|
|
894
|
+
const { username, otp, magicLink = "", brandName, logoUrl, extraMessage, footer } = params;
|
|
868
895
|
const brand = this.resolveBrand(brandName);
|
|
869
896
|
const body = `Hi ${username},<br/>Use the code below or click the button to complete your login.`;
|
|
870
897
|
const plainLink = magicLink ? `\n\nAlternatively, verify here:\n${magicLink}` : "";
|
|
898
|
+
const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
|
|
899
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
900
|
+
const plainTextBody = htmlToPlainText(body) + `\n\nYour verification code is: ${otp}` + plainLink;
|
|
871
901
|
return {
|
|
872
902
|
subject: "Your Login Verification Code",
|
|
873
903
|
header: "Two-Factor Authentication",
|
|
874
904
|
body,
|
|
875
|
-
logoUrl: this.defaultLogoUrl,
|
|
905
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
876
906
|
otpCode: otp,
|
|
877
907
|
actionUrl: magicLink || void 0,
|
|
878
908
|
actionText: magicLink ? "Verify Login" : void 0,
|
|
879
|
-
extraMessage:
|
|
880
|
-
footer:
|
|
909
|
+
extraMessage: resolvedExtraMessage,
|
|
910
|
+
footer: resolvedFooter,
|
|
881
911
|
userName: username,
|
|
882
912
|
fromName: brand,
|
|
883
|
-
noHtmlMessage:
|
|
913
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
|
|
884
914
|
};
|
|
885
915
|
}
|
|
886
916
|
/**
|
|
887
917
|
* Magic link sign-in email (no OTP, button only).
|
|
888
918
|
*/
|
|
889
919
|
createMagicLinkEmail(params) {
|
|
890
|
-
const { username, magicLink, brandName } = params;
|
|
920
|
+
const { username, magicLink, brandName, logoUrl, extraMessage, footer } = params;
|
|
891
921
|
const brand = this.resolveBrand(brandName);
|
|
892
922
|
const body = `Hi ${username},<br/>Click the button below to sign in. No password needed.`;
|
|
923
|
+
const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
|
|
924
|
+
const resolvedFooter = footer ?? this.buildFooter(brand);
|
|
925
|
+
const plainTextBody = htmlToPlainText(body) + `\n\nSign in here:\n${magicLink}`;
|
|
893
926
|
return {
|
|
894
927
|
subject: "Your Magic Link",
|
|
895
928
|
header: `Sign In to ${brand}`,
|
|
896
929
|
body,
|
|
897
|
-
logoUrl: this.defaultLogoUrl,
|
|
930
|
+
logoUrl: logoUrl ?? this.defaultLogoUrl,
|
|
898
931
|
actionUrl: magicLink,
|
|
899
932
|
actionText: "Sign In",
|
|
900
|
-
extraMessage:
|
|
901
|
-
footer:
|
|
933
|
+
extraMessage: resolvedExtraMessage,
|
|
934
|
+
footer: resolvedFooter,
|
|
902
935
|
userName: username,
|
|
903
936
|
fromName: brand,
|
|
904
|
-
noHtmlMessage:
|
|
937
|
+
noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
|
|
905
938
|
};
|
|
906
939
|
}
|
|
907
940
|
static _defaultInstance;
|
|
@@ -948,5 +981,5 @@ function buildPlainTextTemplate(dto, _options) {
|
|
|
948
981
|
}
|
|
949
982
|
|
|
950
983
|
//#endregion
|
|
951
|
-
export { ConfigurationError, ConsoleEmailSender, CpaasHttpSender,
|
|
984
|
+
export { ConfigurationError, ConsoleEmailSender, CpaasHttpSender, DefaultEmailRenderer, EmailTemplateFactory, MailKit, MailKitError, MemoryEmailSender, TemplateError, TransportError, buildHTMLTemplate, buildHtml, buildPlainText, buildPlainTextTemplate, createMailKit, decodeHtmlEntities, htmlToPlainText, isValidHttpUrl, normalizeRecipient, normalizeRecipients, parseEmailAddress };
|
|
952
985
|
//# sourceMappingURL=index.js.map
|