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/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`; `ZeptoMailHttpSender` is a deprecated alias).
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:
@@ -1,9 +1,8 @@
1
1
  import type { IEmailSender } from "../transports/sender.interface.js";
2
2
  import type { IEmailRenderer, RenderedEmail } from "../renderers/renderer.interface.js";
3
3
  import type { EmailTemplateDto } from "../templates/dto/index.js";
4
- import { type Recipient, type SendMailOptions, type SendResult } from "./types.js";
5
- import type { BulkKnownTemplateSendOptions, KnownTemplateSendOptions, SendBulkMailOptions } from "./bulk-types.js";
6
- export interface SendTemplateOptions {
4
+ import { type BulkKnownTemplateSendOptions, type KnownTemplateSendOptions, type MailAddressOptions, type MailMetadataOptions, type Recipient, type SendBulkMailOptions, type SendMailOptions, type SendResult } from "./types.js";
5
+ export interface SendTemplateOptions extends MailAddressOptions, MailMetadataOptions {
7
6
  /**
8
7
  * One or more recipient email addresses.
9
8
  */
@@ -20,42 +19,10 @@ export interface SendTemplateOptions {
20
19
  * Optional sender display name override for this specific email.
21
20
  */
22
21
  fromName?: string;
23
- /**
24
- * Optional sender email address override.
25
- */
26
- from?: Recipient;
27
- /**
28
- * Optional CC recipients.
29
- */
30
- cc?: Recipient | Recipient[];
31
- /**
32
- * Optional BCC recipients.
33
- */
34
- bcc?: Recipient | Recipient[];
35
- /**
36
- * Optional Reply-To recipients.
37
- */
38
- replyTo?: Recipient | Recipient[];
39
- /**
40
- * Optional file attachments.
41
- */
42
- attachments?: SendMailOptions["attachments"];
43
- /**
44
- * Optional custom headers.
45
- */
46
- headers?: Record<string, string>;
47
- /**
48
- * Optional tags for tracking.
49
- */
50
- tags?: string[];
51
- /**
52
- * Optional metadata.
53
- */
54
- metadata?: Record<string, string>;
55
22
  }
56
23
  export interface MailKitOptions {
57
24
  /**
58
- * The transport adapter used to dispatch emails (e.g. ZeptoMailHttpSender, MemoryEmailSender).
25
+ * The transport adapter used to dispatch emails (e.g. CpaasHttpSender, MemoryEmailSender).
59
26
  */
60
27
  transport: IEmailSender;
61
28
  /**
@@ -107,15 +74,12 @@ export declare class MailKit {
107
74
  */
108
75
  sendMail(options: SendTemplateOptions): Promise<SendResult>;
109
76
  /**
110
- * @deprecated Use {@link sendMail} instead.
111
- */
112
- send(options: SendTemplateOptions): Promise<SendResult>;
113
- /**
114
- * Sends a bulk email using a strongly-typed template DTO.
77
+ * Sends the same rendered template DTO to every recipient in a single batch.
115
78
  *
116
79
  * The transport delivers an individual copy to each recipient, so
117
- * recipients are not exposed to one another. Per-recipient personalization
118
- * 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`.
119
83
  *
120
84
  * Example:
121
85
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"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"}
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"}
@@ -1,3 +1,4 @@
1
+ import type { EmailTemplateDto } from "../templates/dto/index.js";
1
2
  /**
2
3
  * Standard email address representation with optional display name.
3
4
  */
@@ -5,6 +6,15 @@ export interface EmailAddress {
5
6
  address: string;
6
7
  name?: string;
7
8
  }
9
+ /**
10
+ * A recipient with optional provider-side merge variables.
11
+ */
12
+ export interface BulkRecipient extends EmailAddress {
13
+ /**
14
+ * Provider-side merge variables (e.g. Zoho CPaaS `merge_info`).
15
+ */
16
+ mergeInfo?: Record<string, string>;
17
+ }
8
18
  /**
9
19
  * Flexible recipient representation allowing string ('user@example.com'),
10
20
  * EmailAddress ({ address: 'user@example.com', name: 'User' }),
@@ -44,22 +54,132 @@ export interface EmailAttachment {
44
54
  cid?: string;
45
55
  }
46
56
  /**
47
- * Options for sending an email through a transport adapter.
57
+ * Common sender and recipient addressing options.
48
58
  */
49
- export interface SendMailOptions {
50
- to: Recipient | Recipient[];
59
+ export interface MailAddressOptions {
60
+ /**
61
+ * Optional sender address override.
62
+ */
51
63
  from?: Recipient;
52
- subject: string;
53
- html: string;
54
- text?: string;
64
+ /**
65
+ * Optional CC recipients.
66
+ */
55
67
  cc?: Recipient | Recipient[];
68
+ /**
69
+ * Optional BCC recipients.
70
+ */
56
71
  bcc?: Recipient | Recipient[];
72
+ /**
73
+ * Optional Reply-To recipients.
74
+ */
57
75
  replyTo?: Recipient | Recipient[];
76
+ /**
77
+ * Optional file attachments.
78
+ */
58
79
  attachments?: EmailAttachment[];
80
+ }
81
+ /**
82
+ * Common custom header, tag, and metadata options.
83
+ */
84
+ export interface MailMetadataOptions {
85
+ /**
86
+ * Optional custom headers.
87
+ */
59
88
  headers?: Record<string, string>;
89
+ /**
90
+ * Optional tags for tracking.
91
+ */
60
92
  tags?: string[];
93
+ /**
94
+ * Optional metadata.
95
+ */
61
96
  metadata?: Record<string, string>;
62
97
  }
98
+ /**
99
+ * Common provider tracking and reference options.
100
+ */
101
+ export interface TrackingOptions {
102
+ /**
103
+ * Enable or disable click tracking.
104
+ */
105
+ trackClicks?: boolean;
106
+ /**
107
+ * Enable or disable open tracking.
108
+ */
109
+ trackOpens?: boolean;
110
+ /**
111
+ * Verified bounce (Return-Path) address.
112
+ */
113
+ bounceAddress?: string;
114
+ /**
115
+ * Custom reference string to identify the email in your system.
116
+ */
117
+ clientReference?: string;
118
+ }
119
+ /**
120
+ * Options for sending an email through a transport adapter.
121
+ */
122
+ export interface SendMailOptions extends MailAddressOptions, MailMetadataOptions {
123
+ to: Recipient | Recipient[];
124
+ subject: string;
125
+ html: string;
126
+ text?: string;
127
+ }
128
+ /**
129
+ * Transport-level batch of a single raw email content to many recipients.
130
+ *
131
+ * The provider delivers an individual copy to each recipient, so recipients
132
+ * are not exposed to one another.
133
+ */
134
+ export type BulkSendOptions = SendMailOptions & TrackingOptions;
135
+ /**
136
+ * Options for sending a single email using a provider-side template.
137
+ */
138
+ export interface KnownTemplateSendOptions extends MailAddressOptions, TrackingOptions {
139
+ /**
140
+ * Provider-side template identifier (e.g. Zoho `template_key`).
141
+ */
142
+ templateId: string;
143
+ /**
144
+ * Recipient email address.
145
+ */
146
+ to: Recipient;
147
+ /**
148
+ * Template variable substitutions.
149
+ */
150
+ mergeInfo?: Record<string, string>;
151
+ }
152
+ /**
153
+ * Options for sending a batch of emails using a provider-side template.
154
+ *
155
+ * Each recipient may carry its own `mergeInfo` so the provider can
156
+ * personalize the template per recipient.
157
+ */
158
+ export interface BulkKnownTemplateSendOptions extends MailAddressOptions, TrackingOptions {
159
+ /**
160
+ * Provider-side template identifier (e.g. Zoho `template_key`).
161
+ */
162
+ templateId: string;
163
+ /**
164
+ * Recipients, each with optional per-recipient merge variables.
165
+ */
166
+ to: BulkRecipient[];
167
+ }
168
+ /**
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`.
172
+ */
173
+ export interface SendBulkMailOptions extends MailAddressOptions, MailMetadataOptions, TrackingOptions {
174
+ /**
175
+ * Templated email DTO rendered once and sent to every recipient.
176
+ */
177
+ template: EmailTemplateDto;
178
+ /**
179
+ * One or more recipient email addresses.
180
+ */
181
+ to: Recipient | Recipient[];
182
+ }
63
183
  /**
64
184
  * Result returned by an IEmailSender upon dispatch.
65
185
  */
@@ -68,9 +188,5 @@ export interface SendResult {
68
188
  messageId?: string;
69
189
  /** Raw provider response (e.g. Zoho CPaaS JSON body). */
70
190
  rawResponse?: unknown;
71
- /**
72
- * @deprecated Use `rawResponse` instead.
73
- */
74
- response?: unknown;
75
191
  }
76
192
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,YAAY,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAa7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,YAAY,CAcrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,YAAY,EAAE,CAIxF;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
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,17 +259,12 @@ var MailKit = class {
259
259
  });
260
260
  }
261
261
  /**
262
- * @deprecated Use {@link sendMail} instead.
263
- */
264
- async send(options) {
265
- return await this.sendMail(options);
266
- }
267
- /**
268
- * Sends a bulk email using a strongly-typed template DTO.
262
+ * Sends the same rendered template DTO to every recipient in a single batch.
269
263
  *
270
264
  * The transport delivers an individual copy to each recipient, so
271
- * recipients are not exposed to one another. Per-recipient personalization
272
- * 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`.
273
268
  *
274
269
  * Example:
275
270
  * ```ts
@@ -301,7 +296,9 @@ var MailKit = class {
301
296
  tags: options.tags,
302
297
  metadata: options.metadata,
303
298
  trackClicks: options.trackClicks,
304
- trackOpens: options.trackOpens
299
+ trackOpens: options.trackOpens,
300
+ bounceAddress: options.bounceAddress,
301
+ clientReference: options.clientReference
305
302
  });
306
303
  }
307
304
  /**
@@ -364,7 +361,12 @@ function createMailKit(options) {
364
361
  //#endregion
365
362
  //#region src/transports/cpaas/cpaas-sender.ts
366
363
  /**
367
- * Zoho CPaaS (formerly ZeptoMail) transactional email HTTP transport adapter.
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
+ /**
369
+ * Zoho CPaaS transactional email HTTP transport adapter.
368
370
  *
369
371
  * Uses the standard global `fetch` API for zero-dependency, universal edge
370
372
  * compatibility (Node.js, Bun, Deno, Cloudflare Workers).
@@ -374,6 +376,9 @@ function createMailKit(options) {
374
376
  * - `sendBulk` — batch raw email (`POST /v1.1/email/batch`)
375
377
  * - `sendKnownTemplate` — single template email (`POST /v1.1/email/template`)
376
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.
377
382
  */
378
383
  var CpaasHttpSender = class {
379
384
  name = "cpaas";
@@ -426,7 +431,16 @@ var CpaasHttpSender = class {
426
431
  const payload = this.buildBatchTemplatePayload(options);
427
432
  return await this.post(`${this.apiBase}/email/template/batch`, payload);
428
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
+ }
429
442
  buildSendPayload(options) {
443
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
430
444
  const toRecipients = normalizeRecipients(options.to);
431
445
  if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
432
446
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
@@ -447,6 +461,7 @@ var CpaasHttpSender = class {
447
461
  return payload;
448
462
  }
449
463
  buildTemplatePayload(options) {
464
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
450
465
  const toRecipients = normalizeRecipients(options.to);
451
466
  if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
452
467
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
@@ -466,6 +481,7 @@ var CpaasHttpSender = class {
466
481
  return payload;
467
482
  }
468
483
  buildBatchTemplatePayload(options) {
484
+ this.assertRecipientLimit(options.to, options.cc, options.bcc);
469
485
  if (!options.to || options.to.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
470
486
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
471
487
  const payload = {
@@ -570,8 +586,7 @@ var CpaasHttpSender = class {
570
586
  return {
571
587
  success: true,
572
588
  messageId: responseData?.data?.[0]?.message_id,
573
- rawResponse: responseData,
574
- response: responseData
589
+ rawResponse: responseData
575
590
  };
576
591
  }
577
592
  };
@@ -592,12 +607,10 @@ var MemoryEmailSender = class {
592
607
  result(prefix) {
593
608
  const id = this.nextId++;
594
609
  const messageId = prefix ? `mem-${prefix}-${id}-${Date.now()}` : `mem-${id}-${Date.now()}`;
595
- const rawResponse = { id: messageId };
596
610
  return {
597
611
  success: true,
598
612
  messageId,
599
- rawResponse,
600
- response: rawResponse
613
+ rawResponse: { id: messageId }
601
614
  };
602
615
  }
603
616
  async send(options) {
@@ -739,12 +752,10 @@ var ConsoleEmailSender = class {
739
752
  }
740
753
  lines.push(`└${separator}┘\n`);
741
754
  this.log(lines.join("\n"));
742
- const rawResponse = { logged: true };
743
755
  return {
744
756
  success: true,
745
757
  messageId,
746
- rawResponse,
747
- response: rawResponse
758
+ rawResponse: { logged: true }
748
759
  };
749
760
  }
750
761
  };
@@ -779,130 +790,152 @@ var EmailTemplateFactory = class EmailTemplateFactory {
779
790
  buildFooter(brandName) {
780
791
  return this.footerResolver(brandName);
781
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
+ }
782
799
  /**
783
800
  * Welcome / email-verification email sent after registration.
784
801
  */
785
802
  createEmailVerification(params) {
786
- const { username, verificationUrl, otp, brandName } = params;
803
+ const { username, verificationUrl, otp, brandName, logoUrl, extraMessage, footer } = params;
787
804
  const brand = this.resolveBrand(brandName);
788
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}`;
789
809
  return {
790
810
  subject: "Verify Your Email Address",
791
811
  header: `Welcome to ${brand}!`,
792
812
  body,
793
- logoUrl: this.defaultLogoUrl,
813
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
794
814
  otpCode: otp,
795
815
  actionUrl: verificationUrl,
796
816
  actionText: "Verify Email",
797
- extraMessage: this.defaultSecurityMessage,
798
- footer: this.buildFooter(brand),
817
+ extraMessage: resolvedExtraMessage,
818
+ footer: resolvedFooter,
799
819
  userName: username,
800
820
  fromName: brand,
801
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}\n\nAlternatively, verify here:\n${verificationUrl}`
821
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
802
822
  };
803
823
  }
804
824
  /**
805
825
  * Password-reset email with an optional OTP code and action link.
806
826
  */
807
827
  createPasswordReset(params) {
808
- const { username, resetUrl, otp = "", brandName } = params;
828
+ const { username, resetUrl, otp = "", brandName, logoUrl, extraMessage, footer } = params;
809
829
  const brand = this.resolveBrand(brandName);
810
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.`;
811
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}`;
812
835
  return {
813
836
  subject: "Password Reset Request",
814
837
  header: "Reset Your Password",
815
838
  body,
816
- logoUrl: this.defaultLogoUrl,
839
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
817
840
  otpCode: otp || void 0,
818
841
  actionUrl: resetUrl,
819
842
  actionText: "Reset Password",
820
- extraMessage: this.defaultSecurityMessage,
821
- footer: this.buildFooter(brand),
843
+ extraMessage: resolvedExtraMessage,
844
+ footer: resolvedFooter,
822
845
  userName: username,
823
846
  fromName: brand,
824
- 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)
825
848
  };
826
849
  }
827
850
  /**
828
851
  * Generic plain message email (no action button, no OTP).
829
852
  */
830
853
  createSimpleMessage(params) {
831
- const { subject, header, body, brandName } = params;
854
+ const { subject, header, body, brandName, logoUrl, extraMessage, footer } = params;
832
855
  const brand = this.resolveBrand(brandName);
856
+ const resolvedFooter = footer ?? this.buildFooter(brand);
833
857
  return {
834
858
  subject,
835
859
  header,
836
860
  body,
837
- logoUrl: this.defaultLogoUrl,
838
- footer: this.buildFooter(brand),
861
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
862
+ extraMessage,
863
+ footer: resolvedFooter,
839
864
  fromName: brand,
840
- noHtmlMessage: htmlToPlainText(body)
865
+ noHtmlMessage: this.arrangePlainTextWithExtras(htmlToPlainText(body), extraMessage, resolvedFooter)
841
866
  };
842
867
  }
843
868
  /**
844
869
  * Newsletter / announcement email with an optional hero image and CTA button.
845
870
  */
846
871
  createNewsLetter(params) {
847
- const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl } = params;
872
+ const { subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl, extraMessage, footer } = params;
848
873
  const brand = this.resolveBrand(brandName);
849
- let noHtmlMessage = htmlToPlainText(body);
850
- 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}`;
851
877
  return {
852
878
  subject,
853
879
  header,
854
880
  body,
855
- logoUrl: logoUrl || this.defaultLogoUrl,
881
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
856
882
  imageUrl,
857
883
  actionUrl,
858
884
  actionText,
859
- footer: this.buildFooter(brand),
885
+ extraMessage,
886
+ footer: resolvedFooter,
860
887
  fromName: brand,
861
- noHtmlMessage
888
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, extraMessage, resolvedFooter)
862
889
  };
863
890
  }
864
891
  /**
865
892
  * Two-factor authentication email with OTP code and optional magic link.
866
893
  */
867
894
  create2FAEmail(params) {
868
- const { username, otp, magicLink = "", brandName } = params;
895
+ const { username, otp, magicLink = "", brandName, logoUrl, extraMessage, footer } = params;
869
896
  const brand = this.resolveBrand(brandName);
870
897
  const body = `Hi ${username},<br/>Use the code below or click the button to complete your login.`;
871
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;
872
902
  return {
873
903
  subject: "Your Login Verification Code",
874
904
  header: "Two-Factor Authentication",
875
905
  body,
876
- logoUrl: this.defaultLogoUrl,
906
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
877
907
  otpCode: otp,
878
908
  actionUrl: magicLink || void 0,
879
909
  actionText: magicLink ? "Verify Login" : void 0,
880
- extraMessage: this.defaultSecurityMessage,
881
- footer: this.buildFooter(brand),
910
+ extraMessage: resolvedExtraMessage,
911
+ footer: resolvedFooter,
882
912
  userName: username,
883
913
  fromName: brand,
884
- noHtmlMessage: htmlToPlainText(body) + `\n\nYour verification code is: ${otp}` + plainLink
914
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
885
915
  };
886
916
  }
887
917
  /**
888
918
  * Magic link sign-in email (no OTP, button only).
889
919
  */
890
920
  createMagicLinkEmail(params) {
891
- const { username, magicLink, brandName } = params;
921
+ const { username, magicLink, brandName, logoUrl, extraMessage, footer } = params;
892
922
  const brand = this.resolveBrand(brandName);
893
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}`;
894
927
  return {
895
928
  subject: "Your Magic Link",
896
929
  header: `Sign In to ${brand}`,
897
930
  body,
898
- logoUrl: this.defaultLogoUrl,
931
+ logoUrl: logoUrl ?? this.defaultLogoUrl,
899
932
  actionUrl: magicLink,
900
933
  actionText: "Sign In",
901
- extraMessage: this.defaultSecurityMessage,
902
- footer: this.buildFooter(brand),
934
+ extraMessage: resolvedExtraMessage,
935
+ footer: resolvedFooter,
903
936
  userName: username,
904
937
  fromName: brand,
905
- noHtmlMessage: htmlToPlainText(body) + `\n\nSign in here:\n${magicLink}`
938
+ noHtmlMessage: this.arrangePlainTextWithExtras(plainTextBody, resolvedExtraMessage, resolvedFooter)
906
939
  };
907
940
  }
908
941
  static _defaultInstance;
@@ -959,7 +992,6 @@ exports.MailKitError = MailKitError;
959
992
  exports.MemoryEmailSender = MemoryEmailSender;
960
993
  exports.TemplateError = TemplateError;
961
994
  exports.TransportError = TransportError;
962
- exports.ZeptoMailHttpSender = CpaasHttpSender;
963
995
  exports.buildHTMLTemplate = buildHTMLTemplate;
964
996
  exports.buildHtml = buildHtml;
965
997
  exports.buildPlainText = buildPlainText;