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.
Files changed (36) hide show
  1. package/README.md +6 -2
  2. package/dist/core/client.d.ts +7 -43
  3. package/dist/core/client.d.ts.map +1 -1
  4. package/dist/core/types.d.ts +126 -10
  5. package/dist/core/types.d.ts.map +1 -1
  6. package/dist/index.cjs +82 -50
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +0 -5
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +83 -50
  11. package/dist/index.js.map +1 -1
  12. package/dist/renderers/default/default-renderer.d.ts +5 -22
  13. package/dist/renderers/default/default-renderer.d.ts.map +1 -1
  14. package/dist/renderers/renderer.interface.d.ts +25 -0
  15. package/dist/renderers/renderer.interface.d.ts.map +1 -1
  16. package/dist/templates/dto/index.d.ts +13 -24
  17. package/dist/templates/dto/index.d.ts.map +1 -1
  18. package/dist/templates/factory.d.ts +1 -0
  19. package/dist/templates/factory.d.ts.map +1 -1
  20. package/dist/templates/template-builder.d.ts +2 -19
  21. package/dist/templates/template-builder.d.ts.map +1 -1
  22. package/dist/transports/console/console-sender.d.ts +1 -1
  23. package/dist/transports/console/console-sender.d.ts.map +1 -1
  24. package/dist/transports/cpaas/cpaas-sender.d.ts +10 -2
  25. package/dist/transports/cpaas/cpaas-sender.d.ts.map +1 -1
  26. package/dist/transports/memory/memory-sender.d.ts +1 -1
  27. package/dist/transports/memory/memory-sender.d.ts.map +1 -1
  28. package/dist/transports/sender.interface.d.ts +1 -1
  29. package/dist/transports/sender.interface.d.ts.map +1 -1
  30. package/package.json +2 -2
  31. package/dist/core/bulk-types.d.ts +0 -196
  32. package/dist/core/bulk-types.d.ts.map +0 -1
  33. package/dist/transports/zeptomail/types.d.ts +0 -6
  34. package/dist/transports/zeptomail/types.d.ts.map +0 -1
  35. package/dist/transports/zeptomail/zeptomail-sender.d.ts +0 -7
  36. 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
- * @deprecated Use {@link sendMail} instead.
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. Per-recipient personalization
271
- * is available via {@link sendBulkKnownTemplate}.
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 (formerly ZeptoMail) transactional email HTTP transport adapter.
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: this.defaultSecurityMessage,
797
- footer: this.buildFooter(brand),
816
+ extraMessage: resolvedExtraMessage,
817
+ footer: resolvedFooter,
798
818
  userName: username,
799
819
  fromName: brand,
800
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}\n\nAlternatively, verify here:\n${verificationUrl}`
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: this.defaultSecurityMessage,
820
- footer: this.buildFooter(brand),
842
+ extraMessage: resolvedExtraMessage,
843
+ footer: resolvedFooter,
821
844
  userName: username,
822
845
  fromName: brand,
823
- noHtmlMessage: htmlToPlainText(body) + plainTextOtp + `\n\nAlternatively, you can use the following link to reset your password:\n${resetUrl}`
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
- footer: this.buildFooter(brand),
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
- let noHtmlMessage = htmlToPlainText(body);
849
- if (actionUrl) noHtmlMessage += `\n\n${actionText || "Learn more"}: ${actionUrl}`;
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 || this.defaultLogoUrl,
880
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
855
881
  imageUrl,
856
882
  actionUrl,
857
883
  actionText,
858
- footer: this.buildFooter(brand),
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: this.defaultSecurityMessage,
880
- footer: this.buildFooter(brand),
909
+ extraMessage: resolvedExtraMessage,
910
+ footer: resolvedFooter,
881
911
  userName: username,
882
912
  fromName: brand,
883
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}` + plainLink
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: this.defaultSecurityMessage,
901
- footer: this.buildFooter(brand),
933
+ extraMessage: resolvedExtraMessage,
934
+ footer: resolvedFooter,
902
935
  userName: username,
903
936
  fromName: brand,
904
- noHtmlMessage: htmlToPlainText(body) + `\n\nSign in here:\n${magicLink}`
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, CpaasHttpSender as ZeptoMailHttpSender, DefaultEmailRenderer, EmailTemplateFactory, MailKit, MailKitError, MemoryEmailSender, TemplateError, TransportError, buildHTMLTemplate, buildHtml, buildPlainText, buildPlainTextTemplate, createMailKit, decodeHtmlEntities, htmlToPlainText, isValidHttpUrl, normalizeRecipient, normalizeRecipients, parseEmailAddress };
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