ts-mailkit 3.0.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 CHANGED
@@ -10,7 +10,7 @@ Works seamlessly in **Node.js**, **Cloudflare Workers** (`workerd`), **Bun**, **
10
10
 
11
11
  - **Type-Safe DTOs**: Strongly-typed Data Transfer Objects for transactional emails (verification, password reset, 2FA, magic links, newsletters).
12
12
  - **Pluggable Transports (`IEmailSender`)**: Decoupled transport adapter interface with built-in senders:
13
- - `CpaasHttpSender` (Zoho CPaaS transactional API via native `fetch`).
13
+ - `CpaasHttpSender` (Zoho CPaaS transactional API via native `fetch`; rejects requests over 500 recipients before dispatch).
14
14
  - `MemoryEmailSender` (In-memory mock transport for unit and integration testing).
15
15
  - `ConsoleEmailSender` (Formatted terminal logger for local development).
16
16
  - **Zero Runtime Dependencies**: Core uses standard web APIs (global `fetch`), ensuring zero heavy dependencies and complete edge compatibility.
@@ -261,7 +261,9 @@ export class CustomSmtpSender implements IEmailSender {
261
261
  `MailKit` exposes four canonical send methods. Bulk methods hit the provider's batch endpoints directly (no client-side loops) and deliver an individual copy to each recipient.
262
262
 
263
263
  ```ts
264
- // 1. Bulk manual template: one rendered DTO, delivered individually to every recipient.
264
+ // 1. Bulk manual template: the SAME rendered DTO is delivered individually
265
+ // to every recipient (one batch call). For per-recipient content, use
266
+ // sendBulkKnownTemplate below.
265
267
  await mailer.sendBulkMail({
266
268
  to: ["a@example.com", "b@example.com"],
267
269
  template: newsletterDto,
@@ -288,6 +290,8 @@ await mailer.sendBulkKnownTemplate({
288
290
 
289
291
  Set `CpaasHttpConfig.preferTemplateAlias: true` to send `template_alias` instead of `template_key`. Every transport returns a unified `SendResult` whose `rawResponse` field holds the provider's raw response (typed via the exported `CpaasSuccessResponse` / `CpaasErrorResponse` types).
290
292
 
293
+ > **Recipient limit:** Zoho CPaaS accepts at most **500 recipients per request**, counted across `to`, `cc`, and `bcc`. `CpaasHttpSender` validates this before making any network request and throws a `TransportError` when exceeded.
294
+
291
295
  ### 8. Building Upload-Ready Templates
292
296
 
293
297
  `buildHTMLTemplate` and `buildPlainTextTemplate` turn the canonical `EmailTemplateDto` into content you can upload to a messaging platform:
@@ -74,11 +74,12 @@ export declare class MailKit {
74
74
  */
75
75
  sendMail(options: SendTemplateOptions): Promise<SendResult>;
76
76
  /**
77
- * Sends a bulk email using a strongly-typed template DTO.
77
+ * Sends the same rendered template DTO to every recipient in a single batch.
78
78
  *
79
79
  * The transport delivers an individual copy to each recipient, so
80
- * recipients are not exposed to one another. Per-recipient personalization
81
- * is available via {@link sendBulkKnownTemplate}.
80
+ * recipients are not exposed to one another. The content is identical for
81
+ * everyone; for per-recipient content, use {@link sendBulkKnownTemplate}
82
+ * with a provider-side template and `mergeInfo`.
82
83
  *
83
84
  * Example:
84
85
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAGxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB,EAAE,mBAAmB;IAClF;;OAEG;IACH,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC5B;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,SAAS,EAAE,YAAY,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAiC;IAEpE,YAAY,OAAO,EAAE,cAAc,EASlC;IAED;;OAEG;IACH,YAAY,IAAI,YAAY,CAE3B;IAED;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAE/D;IAED;;;;;;;;;;OAUG;IACG,QAAQ,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkChE;IAED;;;;;;;;;;;;;;OAcG;IACG,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiCpE;IAED;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC,CAY9E;IAED;;;OAGG;IACG,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,UAAU,CAAC,CAYtF;YAEa,eAAe;IAc7B,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAQ3D;CACF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAE9D"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAGxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB,EAAE,mBAAmB;IAClF;;OAEG;IACH,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC5B;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAC;IAC3B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B;;OAEG;IACH,SAAS,EAAE,YAAY,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpD;AAED;;GAEG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAY;IACzC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAiC;IAEpE,YAAY,OAAO,EAAE,cAAc,EASlC;IAED;;OAEG;IACH,YAAY,IAAI,YAAY,CAE3B;IAED;;OAEG;IACG,MAAM,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAE/D;IAED;;;;;;;;;;OAUG;IACG,QAAQ,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAkChE;IAED;;;;;;;;;;;;;;;OAeG;IACG,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,CAiCpE;IAED;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,UAAU,CAAC,CAY9E;IAED;;;OAGG;IACG,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,UAAU,CAAC,CAYtF;YAEa,eAAe;IAc7B,OAAO,CAAC,aAAa;IAWrB;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAQ3D;CACF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAE9D"}
@@ -166,11 +166,13 @@ export interface BulkKnownTemplateSendOptions extends MailAddressOptions, Tracki
166
166
  to: BulkRecipient[];
167
167
  }
168
168
  /**
169
- * Client-level options for sending a bulk email using the in-built template DTO.
169
+ * Client-level options for sending the same in-built template DTO to many
170
+ * recipients. For per-recipient content, use `sendBulkKnownTemplate` with a
171
+ * provider-side template and `mergeInfo`.
170
172
  */
171
173
  export interface SendBulkMailOptions extends MailAddressOptions, MailMetadataOptions, TrackingOptions {
172
174
  /**
173
- * Templated email DTO to render and send to every recipient.
175
+ * Templated email DTO rendered once and sent to every recipient.
174
176
  */
175
177
  template: EmailTemplateDto;
176
178
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -259,11 +259,12 @@ var MailKit = class {
259
259
  });
260
260
  }
261
261
  /**
262
- * Sends a bulk email using a strongly-typed template DTO.
262
+ * Sends the same rendered template DTO to every recipient in a single batch.
263
263
  *
264
264
  * The transport delivers an individual copy to each recipient, so
265
- * recipients are not exposed to one another. Per-recipient personalization
266
- * is available via {@link sendBulkKnownTemplate}.
265
+ * recipients are not exposed to one another. The content is identical for
266
+ * everyone; for per-recipient content, use {@link sendBulkKnownTemplate}
267
+ * with a provider-side template and `mergeInfo`.
267
268
  *
268
269
  * Example:
269
270
  * ```ts
@@ -360,6 +361,11 @@ function createMailKit(options) {
360
361
  //#endregion
361
362
  //#region src/transports/cpaas/cpaas-sender.ts
362
363
  /**
364
+ * Zoho CPaaS accepts at most 500 recipients per request, counted across
365
+ * `to`, `cc`, and `bcc`.
366
+ */
367
+ const CPAAS_MAX_RECIPIENTS = 500;
368
+ /**
363
369
  * Zoho CPaaS transactional email HTTP transport adapter.
364
370
  *
365
371
  * Uses the standard global `fetch` API for zero-dependency, universal edge
@@ -370,6 +376,9 @@ function createMailKit(options) {
370
376
  * - `sendBulk` — batch raw email (`POST /v1.1/email/batch`)
371
377
  * - `sendKnownTemplate` — single template email (`POST /v1.1/email/template`)
372
378
  * - `sendBulkKnownTemplate` — batch template email (`POST /v1.1/email/template/batch`)
379
+ *
380
+ * Requests exceeding Zoho's 500-recipient limit (across `to`, `cc`, and `bcc`)
381
+ * are rejected before any network call is made.
373
382
  */
374
383
  var CpaasHttpSender = class {
375
384
  name = "cpaas";
@@ -422,7 +431,16 @@ var CpaasHttpSender = class {
422
431
  const payload = this.buildBatchTemplatePayload(options);
423
432
  return await this.post(`${this.apiBase}/email/template/batch`, payload);
424
433
  }
434
+ /**
435
+ * Guards against requests that exceed Zoho CPaaS's per-request recipient
436
+ * limit, counted across `to`, `cc`, and `bcc`.
437
+ */
438
+ assertRecipientLimit(to, cc, bcc) {
439
+ const total = normalizeRecipients(to).length + normalizeRecipients(cc).length + normalizeRecipients(bcc).length;
440
+ 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 });
441
+ }
425
442
  buildSendPayload(options) {
443
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
426
444
  const toRecipients = normalizeRecipients(options.to);
427
445
  if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
428
446
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
@@ -443,6 +461,7 @@ var CpaasHttpSender = class {
443
461
  return payload;
444
462
  }
445
463
  buildTemplatePayload(options) {
464
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
446
465
  const toRecipients = normalizeRecipients(options.to);
447
466
  if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
448
467
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
@@ -462,6 +481,7 @@ var CpaasHttpSender = class {
462
481
  return payload;
463
482
  }
464
483
  buildBatchTemplatePayload(options) {
484
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
465
485
  if (!options.to || options.to.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
466
486
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
467
487
  const payload = {
@@ -770,130 +790,152 @@ var EmailTemplateFactory = class EmailTemplateFactory {
770
790
  buildFooter(brandName) {
771
791
  return this.footerResolver(brandName);
772
792
  }
793
+ arrangePlainTextWithExtras(base, extraMessage, footer) {
794
+ const parts = [base];
795
+ if (extraMessage) parts.push(htmlToPlainText(extraMessage));
796
+ if (footer) parts.push(htmlToPlainText(footer));
797
+ return parts.join("\n\n");
798
+ }
773
799
  /**
774
800
  * Welcome / email-verification email sent after registration.
775
801
  */
776
802
  createEmailVerification(params) {
777
- const { username, verificationUrl, otp, brandName } = params;
803
+ const { username, verificationUrl, otp, brandName, logoUrl, extraMessage, footer } = params;
778
804
  const brand = this.resolveBrand(brandName);
779
805
  const body = `Hi ${username},<br/>Thank you for signing up. Use the code below or click the button to verify your email address.`;
806
+ const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
807
+ const resolvedFooter = footer ?? this.buildFooter(brand);
808
+ const plainTextBody = htmlToPlainText(body) + `\n\nYour verification code is: ${otp}\n\nAlternatively, verify here:\n${verificationUrl}`;
780
809
  return {
781
810
  subject: "Verify Your Email Address",
782
811
  header: `Welcome to ${brand}!`,
783
812
  body,
784
- logoUrl: this.defaultLogoUrl,
813
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
785
814
  otpCode: otp,
786
815
  actionUrl: verificationUrl,
787
816
  actionText: "Verify Email",
788
- extraMessage: this.defaultSecurityMessage,
789
- footer: this.buildFooter(brand),
817
+ extraMessage: resolvedExtraMessage,
818
+ footer: resolvedFooter,
790
819
  userName: username,
791
820
  fromName: brand,
792
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}\n\nAlternatively, verify here:\n${verificationUrl}`
821
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
793
822
  };
794
823
  }
795
824
  /**
796
825
  * Password-reset email with an optional OTP code and action link.
797
826
  */
798
827
  createPasswordReset(params) {
799
- const { username, resetUrl, otp = "", brandName } = params;
828
+ const { username, resetUrl, otp = "", brandName, logoUrl, extraMessage, footer } = params;
800
829
  const brand = this.resolveBrand(brandName);
801
830
  const body = `Hi ${username},<br/>We received a request to reset your password. Use the OTP code below or click the button to proceed.`;
802
831
  const plainTextOtp = otp ? `\n\nYour OTP code is: ${otp}` : "";
832
+ const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
833
+ const resolvedFooter = footer ?? this.buildFooter(brand);
834
+ const plainTextBody = htmlToPlainText(body) + plainTextOtp + `\n\nAlternatively, you can use the following link to reset your password:\n${resetUrl}`;
803
835
  return {
804
836
  subject: "Password Reset Request",
805
837
  header: "Reset Your Password",
806
838
  body,
807
- logoUrl: this.defaultLogoUrl,
839
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
808
840
  otpCode: otp || void 0,
809
841
  actionUrl: resetUrl,
810
842
  actionText: "Reset Password",
811
- extraMessage: this.defaultSecurityMessage,
812
- footer: this.buildFooter(brand),
843
+ extraMessage: resolvedExtraMessage,
844
+ footer: resolvedFooter,
813
845
  userName: username,
814
846
  fromName: brand,
815
- noHtmlMessage: htmlToPlainText(body) + plainTextOtp + `\n\nAlternatively, you can use the following link to reset your password:\n${resetUrl}`
847
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
816
848
  };
817
849
  }
818
850
  /**
819
851
  * Generic plain message email (no action button, no OTP).
820
852
  */
821
853
  createSimpleMessage(params) {
822
- const { subject, header, body, brandName } = params;
854
+ const { subject, header, body, brandName, logoUrl, extraMessage, footer } = params;
823
855
  const brand = this.resolveBrand(brandName);
856
+ const resolvedFooter = footer ?? this.buildFooter(brand);
824
857
  return {
825
858
  subject,
826
859
  header,
827
860
  body,
828
- logoUrl: this.defaultLogoUrl,
829
- footer: this.buildFooter(brand),
861
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
862
+ extraMessage,
863
+ footer: resolvedFooter,
830
864
  fromName: brand,
831
- noHtmlMessage: htmlToPlainText(body)
865
+ noHtmlMessage: this.arrangePlainTextWithExtras(htmlToPlainText(body), extraMessage, resolvedFooter)
832
866
  };
833
867
  }
834
868
  /**
835
869
  * Newsletter / announcement email with an optional hero image and CTA button.
836
870
  */
837
871
  createNewsLetter(params) {
838
- const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl } = params;
872
+ const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl, extraMessage, footer } = params;
839
873
  const brand = this.resolveBrand(brandName);
840
- let noHtmlMessage = htmlToPlainText(body);
841
- if (actionUrl) noHtmlMessage += `\n\n${actionText || "Learn more"}: ${actionUrl}`;
874
+ const resolvedFooter = footer ?? this.buildFooter(brand);
875
+ let plainTextBody = htmlToPlainText(body);
876
+ if (actionUrl) plainTextBody += `\n\n${actionText || "Learn more"}: ${actionUrl}`;
842
877
  return {
843
878
  subject,
844
879
  header,
845
880
  body,
846
- logoUrl: logoUrl || this.defaultLogoUrl,
881
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
847
882
  imageUrl,
848
883
  actionUrl,
849
884
  actionText,
850
- footer: this.buildFooter(brand),
885
+ extraMessage,
886
+ footer: resolvedFooter,
851
887
  fromName: brand,
852
- noHtmlMessage
888
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, extraMessage, resolvedFooter)
853
889
  };
854
890
  }
855
891
  /**
856
892
  * Two-factor authentication email with OTP code and optional magic link.
857
893
  */
858
894
  create2FAEmail(params) {
859
- const { username, otp, magicLink = "", brandName } = params;
895
+ const { username, otp, magicLink = "", brandName, logoUrl, extraMessage, footer } = params;
860
896
  const brand = this.resolveBrand(brandName);
861
897
  const body = `Hi ${username},<br/>Use the code below or click the button to complete your login.`;
862
898
  const plainLink = magicLink ? `\n\nAlternatively, verify here:\n${magicLink}` : "";
899
+ const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
900
+ const resolvedFooter = footer ?? this.buildFooter(brand);
901
+ const plainTextBody = htmlToPlainText(body) + `\n\nYour verification code is: ${otp}` + plainLink;
863
902
  return {
864
903
  subject: "Your Login Verification Code",
865
904
  header: "Two-Factor Authentication",
866
905
  body,
867
- logoUrl: this.defaultLogoUrl,
906
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
868
907
  otpCode: otp,
869
908
  actionUrl: magicLink || void 0,
870
909
  actionText: magicLink ? "Verify Login" : void 0,
871
- extraMessage: this.defaultSecurityMessage,
872
- footer: this.buildFooter(brand),
910
+ extraMessage: resolvedExtraMessage,
911
+ footer: resolvedFooter,
873
912
  userName: username,
874
913
  fromName: brand,
875
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}` + plainLink
914
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
876
915
  };
877
916
  }
878
917
  /**
879
918
  * Magic link sign-in email (no OTP, button only).
880
919
  */
881
920
  createMagicLinkEmail(params) {
882
- const { username, magicLink, brandName } = params;
921
+ const { username, magicLink, brandName, logoUrl, extraMessage, footer } = params;
883
922
  const brand = this.resolveBrand(brandName);
884
923
  const body = `Hi ${username},<br/>Click the button below to sign in. No password needed.`;
924
+ const resolvedExtraMessage = extraMessage ?? this.defaultSecurityMessage;
925
+ const resolvedFooter = footer ?? this.buildFooter(brand);
926
+ const plainTextBody = htmlToPlainText(body) + `\n\nSign in here:\n${magicLink}`;
885
927
  return {
886
928
  subject: "Your Magic Link",
887
929
  header: `Sign In to ${brand}`,
888
930
  body,
889
- logoUrl: this.defaultLogoUrl,
931
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
890
932
  actionUrl: magicLink,
891
933
  actionText: "Sign In",
892
- extraMessage: this.defaultSecurityMessage,
893
- footer: this.buildFooter(brand),
934
+ extraMessage: resolvedExtraMessage,
935
+ footer: resolvedFooter,
894
936
  userName: username,
895
937
  fromName: brand,
896
- noHtmlMessage: htmlToPlainText(body) + `\n\nSign in here:\n${magicLink}`
938
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
897
939
  };
898
940
  }
899
941
  static _defaultInstance;