ts-mailkit 2.0.1 → 3.0.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 (34) hide show
  1. package/README.md +114 -63
  2. package/dist/core/client.d.ts +35 -40
  3. package/dist/core/client.d.ts.map +1 -1
  4. package/dist/core/errors.d.ts +3 -0
  5. package/dist/core/errors.d.ts.map +1 -1
  6. package/dist/core/types.d.ts +126 -7
  7. package/dist/core/types.d.ts.map +1 -1
  8. package/dist/index.cjs +329 -68
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.ts +14 -13
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +327 -68
  13. package/dist/index.js.map +1 -1
  14. package/dist/renderers/default/default-renderer.d.ts +2 -2
  15. package/dist/renderers/renderer.interface.d.ts +1 -1
  16. package/dist/templates/factory.d.ts +1 -1
  17. package/dist/templates/factory.d.ts.map +1 -1
  18. package/dist/templates/template-builder.d.ts +36 -0
  19. package/dist/templates/template-builder.d.ts.map +1 -0
  20. package/dist/transports/console/console-sender.d.ts +7 -2
  21. package/dist/transports/console/console-sender.d.ts.map +1 -1
  22. package/dist/transports/cpaas/cpaas-sender.d.ts +51 -0
  23. package/dist/transports/cpaas/cpaas-sender.d.ts.map +1 -0
  24. package/dist/transports/cpaas/types.d.ts +133 -0
  25. package/dist/transports/cpaas/types.d.ts.map +1 -0
  26. package/dist/transports/memory/memory-sender.d.ts +26 -6
  27. package/dist/transports/memory/memory-sender.d.ts.map +1 -1
  28. package/dist/transports/sender.interface.d.ts +34 -3
  29. package/dist/transports/sender.interface.d.ts.map +1 -1
  30. package/package.json +39 -37
  31. package/dist/transports/zeptomail/types.d.ts +0 -47
  32. package/dist/transports/zeptomail/types.d.ts.map +0 -1
  33. package/dist/transports/zeptomail/zeptomail-sender.d.ts +0 -22
  34. package/dist/transports/zeptomail/zeptomail-sender.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -67,6 +67,8 @@ var TransportError = class extends MailKitError {
67
67
  transportName;
68
68
  statusCode;
69
69
  responseBody;
70
+ /** Parsed raw provider response, when available. */
71
+ rawResponse;
70
72
  cause;
71
73
  constructor(message, options) {
72
74
  super(message);
@@ -74,6 +76,7 @@ var TransportError = class extends MailKitError {
74
76
  this.transportName = options.transportName;
75
77
  this.statusCode = options.statusCode;
76
78
  this.responseBody = options.responseBody;
79
+ this.rawResponse = options.rawResponse;
77
80
  this.cause = options.cause;
78
81
  Object.setPrototypeOf(this, new.target.prototype);
79
82
  }
@@ -220,18 +223,16 @@ var MailKit = class {
220
223
  *
221
224
  * Example:
222
225
  * ```ts
223
- * await mailer.send({
226
+ * await mailer.sendMail({
224
227
  * to: 'user@example.com',
225
228
  * template: myDto,
226
229
  * });
227
230
  * ```
228
231
  */
229
- async send(options) {
232
+ async sendMail(options) {
230
233
  const template = options.template;
231
234
  const recipientName = options.toName ?? template.userName;
232
- let resolvedFromName = options.fromName ?? template.fromName;
233
- if (!resolvedFromName && this.brandNameResolver) resolvedFromName = await this.brandNameResolver();
234
- if (!resolvedFromName) resolvedFromName = this.defaultBrandName;
235
+ const resolvedFromName = await this.resolveFromName(template, options.fromName);
235
236
  const rendered = await this.renderer.render(template);
236
237
  const plaintextBody = template.noHtmlMessage ?? rendered.text;
237
238
  let toRecipients;
@@ -240,11 +241,7 @@ var MailKit = class {
240
241
  name: recipientName
241
242
  };
242
243
  else toRecipients = options.to;
243
- let from = options.from ?? this.defaultFrom;
244
- if (resolvedFromName && from) from = {
245
- address: normalizeRecipient(from).address,
246
- name: resolvedFromName
247
- };
244
+ const from = this.applyFromName(options.from ?? this.defaultFrom, resolvedFromName);
248
245
  return await this.sendRaw({
249
246
  to: toRecipients,
250
247
  from,
@@ -261,6 +258,84 @@ var MailKit = class {
261
258
  });
262
259
  }
263
260
  /**
261
+ * Sends a bulk email using a strongly-typed template DTO.
262
+ *
263
+ * The transport delivers an individual copy to each recipient, so
264
+ * recipients are not exposed to one another. Per-recipient personalization
265
+ * is available via {@link sendBulkKnownTemplate}.
266
+ *
267
+ * Example:
268
+ * ```ts
269
+ * await mailer.sendBulkMail({
270
+ * to: ['a@example.com', 'b@example.com'],
271
+ * template: myDto,
272
+ * });
273
+ * ```
274
+ */
275
+ async sendBulkMail(options) {
276
+ const transport = this.transport;
277
+ if (typeof transport.sendBulk !== "function") throw new ConfigurationError("MailKit: The configured transport does not support bulk sending (sendBulk).");
278
+ const template = options.template;
279
+ const resolvedFromName = await this.resolveFromName(template);
280
+ const rendered = await this.renderer.render(template);
281
+ const plaintextBody = template.noHtmlMessage ?? rendered.text;
282
+ const from = this.applyFromName(options.from ?? this.defaultFrom, resolvedFromName);
283
+ return await transport.sendBulk({
284
+ to: options.to,
285
+ from,
286
+ subject: template.subject,
287
+ html: rendered.html,
288
+ text: plaintextBody,
289
+ cc: options.cc,
290
+ bcc: options.bcc,
291
+ replyTo: options.replyTo,
292
+ attachments: options.attachments,
293
+ headers: options.headers,
294
+ tags: options.tags,
295
+ metadata: options.metadata,
296
+ trackClicks: options.trackClicks,
297
+ trackOpens: options.trackOpens,
298
+ bounceAddress: options.bounceAddress,
299
+ clientReference: options.clientReference
300
+ });
301
+ }
302
+ /**
303
+ * Sends a single email using a provider-side template.
304
+ */
305
+ async sendKnownTemplate(options) {
306
+ const transport = this.transport;
307
+ if (typeof transport.sendKnownTemplate !== "function") throw new ConfigurationError("MailKit: The configured transport does not support template sending (sendKnownTemplate).");
308
+ return await transport.sendKnownTemplate({
309
+ ...options,
310
+ from: options.from ?? this.defaultFrom
311
+ });
312
+ }
313
+ /**
314
+ * Sends a bulk email using a provider-side template with optional
315
+ * per-recipient merge data.
316
+ */
317
+ async sendBulkKnownTemplate(options) {
318
+ const transport = this.transport;
319
+ if (typeof transport.sendBulkKnownTemplate !== "function") throw new ConfigurationError("MailKit: The configured transport does not support bulk template sending (sendBulkKnownTemplate).");
320
+ return await transport.sendBulkKnownTemplate({
321
+ ...options,
322
+ from: options.from ?? this.defaultFrom
323
+ });
324
+ }
325
+ async resolveFromName(template, explicitFromName) {
326
+ let resolved = explicitFromName ?? template.fromName;
327
+ if (!resolved && this.brandNameResolver) resolved = await this.brandNameResolver();
328
+ if (!resolved) resolved = this.defaultBrandName;
329
+ return resolved;
330
+ }
331
+ applyFromName(from, fromName) {
332
+ if (fromName && from) return {
333
+ address: normalizeRecipient(from).address,
334
+ name: fromName
335
+ };
336
+ return from;
337
+ }
338
+ /**
264
339
  * Dispatches a raw, pre-rendered email directly through the transport.
265
340
  * If `options.text` is omitted, plain text is automatically derived from `options.html`.
266
341
  */
@@ -282,38 +357,73 @@ function createMailKit(options) {
282
357
  }
283
358
 
284
359
  //#endregion
285
- //#region src/transports/zeptomail/zeptomail-sender.ts
360
+ //#region src/transports/cpaas/cpaas-sender.ts
286
361
  /**
287
- * ZeptoMail (Zoho Mail transactional email HTTP API) transport adapter.
362
+ * Zoho CPaaS transactional email HTTP transport adapter.
288
363
  *
289
- * Designed for zero dependencies and universal edge compatibility (Node.js, Bun, Deno, Cloudflare Workers)
290
- * by utilizing the standard global `fetch` API.
364
+ * Uses the standard global `fetch` API for zero-dependency, universal edge
365
+ * compatibility (Node.js, Bun, Deno, Cloudflare Workers).
366
+ *
367
+ * Supports:
368
+ * - `send` — single raw email (`POST /v1.1/email`)
369
+ * - `sendBulk` — batch raw email (`POST /v1.1/email/batch`)
370
+ * - `sendKnownTemplate` — single template email (`POST /v1.1/email/template`)
371
+ * - `sendBulkKnownTemplate` — batch template email (`POST /v1.1/email/template/batch`)
291
372
  */
292
- var ZeptoMailHttpSender = class {
293
- name = "zeptomail";
294
- apiUrl;
373
+ var CpaasHttpSender = class {
374
+ name = "cpaas";
375
+ apiBase;
295
376
  authHeader;
296
377
  defaultFrom;
378
+ preferTemplateAlias;
297
379
  fetchImpl;
298
380
  constructor(config) {
299
- if (!config.apiToken || typeof config.apiToken !== "string") throw new ConfigurationError("ZeptoMailHttpSender: Missing or invalid apiToken.");
300
- if (!config.from) throw new ConfigurationError("ZeptoMailHttpSender: Missing required default from address.");
301
- const host = (config.apiHost || "api.zeptomail.com").replace(/^https?:\/\//, "").replace(/\/+$/, "");
302
- this.apiUrl = `https://${host}/v1.1/email`;
381
+ if (!config.apiToken || typeof config.apiToken !== "string") throw new ConfigurationError("CpaasHttpSender: Missing or invalid apiToken.");
382
+ if (!config.from) throw new ConfigurationError("CpaasHttpSender: Missing required default from address.");
383
+ const host = (config.apiHost || "cpaas.zoho.com").replace(/^https?:\/\//, "").replace(/\/+$/, "");
384
+ this.apiBase = `https://${host}/v1.1`;
303
385
  const token = config.apiToken.trim();
304
386
  this.authHeader = token.startsWith("Zoho-") ? token : `Zoho-enczapikey ${token}`;
305
387
  this.defaultFrom = normalizeRecipient(config.from);
306
- if (!this.defaultFrom.address) throw new ConfigurationError("ZeptoMailHttpSender: Configured from address must not be empty.");
388
+ if (!this.defaultFrom.address) throw new ConfigurationError("CpaasHttpSender: Configured from address must not be empty.");
389
+ this.preferTemplateAlias = config.preferTemplateAlias ?? false;
307
390
  const fetchImpl = config.fetch ?? globalThis.fetch;
308
- if (typeof fetchImpl !== "function") throw new ConfigurationError("ZeptoMailHttpSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailHttpConfig if running on Node < 18.");
391
+ if (typeof fetchImpl !== "function") throw new ConfigurationError("CpaasHttpSender: No global fetch implementation found. Pass a custom fetch to CpaasHttpConfig if running on Node < 18.");
309
392
  this.fetchImpl = fetchImpl.bind(globalThis);
310
393
  }
311
394
  /**
312
- * Dispatches an email using Zoho ZeptoMail API v1.1.
395
+ * Dispatches a single raw email using Zoho CPaaS API.
313
396
  */
314
397
  async send(options) {
398
+ const payload = this.buildSendPayload(options);
399
+ return await this.post(`${this.apiBase}/email`, payload);
400
+ }
401
+ /**
402
+ * Dispatches a batch of a single raw email content to many recipients.
403
+ * The provider delivers an individual copy to each recipient.
404
+ */
405
+ async sendBulk(options) {
406
+ const payload = this.buildSendPayload(options);
407
+ return await this.post(`${this.apiBase}/email/batch`, payload);
408
+ }
409
+ /**
410
+ * Dispatches a single email using a provider-side template.
411
+ */
412
+ async sendKnownTemplate(options) {
413
+ const payload = this.buildTemplatePayload(options);
414
+ return await this.post(`${this.apiBase}/email/template`, payload);
415
+ }
416
+ /**
417
+ * Dispatches a batch of emails using a provider-side template, with
418
+ * optional per-recipient merge data.
419
+ */
420
+ async sendBulkKnownTemplate(options) {
421
+ const payload = this.buildBatchTemplatePayload(options);
422
+ return await this.post(`${this.apiBase}/email/template/batch`, payload);
423
+ }
424
+ buildSendPayload(options) {
315
425
  const toRecipients = normalizeRecipients(options.to);
316
- if (toRecipients.length === 0) throw new TransportError("ZeptoMailHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
426
+ if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
317
427
  const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
318
428
  const payload = {
319
429
  from: {
@@ -328,6 +438,52 @@ var ZeptoMailHttpSender = class {
328
438
  htmlbody: options.html,
329
439
  textbody: options.text
330
440
  };
441
+ this.applyCommon(payload, options);
442
+ return payload;
443
+ }
444
+ buildTemplatePayload(options) {
445
+ const toRecipients = normalizeRecipients(options.to);
446
+ if (toRecipients.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
447
+ const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
448
+ const payload = {
449
+ ...this.templateRef(options.templateId),
450
+ from: {
451
+ address: resolvedFrom.address,
452
+ name: resolvedFrom.name
453
+ },
454
+ to: toRecipients.map((r) => ({ email_address: {
455
+ address: r.address,
456
+ name: r.name || ""
457
+ } }))
458
+ };
459
+ if (options.mergeInfo) payload.merge_info = options.mergeInfo;
460
+ this.applyCommon(payload, options);
461
+ return payload;
462
+ }
463
+ buildBatchTemplatePayload(options) {
464
+ if (!options.to || options.to.length === 0) throw new TransportError("CpaasHttpSender: At least one recipient (to) must be specified.", { transportName: this.name });
465
+ const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;
466
+ const payload = {
467
+ ...this.templateRef(options.templateId),
468
+ from: {
469
+ address: resolvedFrom.address,
470
+ name: resolvedFrom.name
471
+ },
472
+ to: options.to.map((r) => ({
473
+ email_address: {
474
+ address: r.address,
475
+ name: r.name || ""
476
+ },
477
+ ...r.mergeInfo ? { merge_info: r.mergeInfo } : {}
478
+ }))
479
+ };
480
+ this.applyCommon(payload, options);
481
+ return payload;
482
+ }
483
+ templateRef(templateId) {
484
+ return this.preferTemplateAlias ? { template_alias: templateId } : { template_key: templateId };
485
+ }
486
+ applyCommon(payload, options) {
331
487
  if (options.cc) {
332
488
  const ccList = normalizeRecipients(options.cc);
333
489
  if (ccList.length > 0) payload.cc = ccList.map((r) => ({ email_address: {
@@ -349,26 +505,33 @@ var ZeptoMailHttpSender = class {
349
505
  name: r.name
350
506
  }));
351
507
  }
352
- if (options.attachments && options.attachments.length > 0) payload.attachments = options.attachments.map((att) => {
353
- let contentBase64;
354
- if (typeof att.content === "string") contentBase64 = att.content;
355
- else if (typeof Buffer !== "undefined") contentBase64 = Buffer.from(att.content).toString("base64");
356
- else {
357
- let binary = "";
358
- const bytes = new Uint8Array(att.content);
359
- for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
360
- contentBase64 = btoa(binary);
361
- }
362
- return {
363
- name: att.filename,
364
- content: contentBase64,
365
- mime_type: att.mimeType || att.contentType || "application/octet-stream",
366
- cid: att.cid
367
- };
368
- });
508
+ if (options.attachments && options.attachments.length > 0) payload.attachments = options.attachments.map((att) => this.toAttachmentPayload(att));
509
+ if (options.trackClicks !== void 0) payload.track_clicks = options.trackClicks;
510
+ if (options.trackOpens !== void 0) payload.track_opens = options.trackOpens;
511
+ if (options.bounceAddress !== void 0) payload.bounce_address = options.bounceAddress;
512
+ if (options.clientReference !== void 0) payload.client_reference = options.clientReference;
513
+ }
514
+ toAttachmentPayload(att) {
515
+ let contentBase64;
516
+ if (typeof att.content === "string") contentBase64 = att.content;
517
+ else if (typeof Buffer !== "undefined") contentBase64 = Buffer.from(att.content).toString("base64");
518
+ else {
519
+ let binary = "";
520
+ const bytes = new Uint8Array(att.content);
521
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
522
+ contentBase64 = btoa(binary);
523
+ }
524
+ return {
525
+ name: att.filename,
526
+ content: contentBase64,
527
+ mime_type: att.mimeType || att.contentType || "application/octet-stream",
528
+ cid: att.cid
529
+ };
530
+ }
531
+ async post(url, payload) {
369
532
  let response;
370
533
  try {
371
- response = await this.fetchImpl(this.apiUrl, {
534
+ response = await this.fetchImpl(url, {
372
535
  method: "POST",
373
536
  headers: {
374
537
  Accept: "application/json",
@@ -378,7 +541,7 @@ var ZeptoMailHttpSender = class {
378
541
  body: JSON.stringify(payload)
379
542
  });
380
543
  } catch (err) {
381
- throw new TransportError(`ZeptoMailHttpSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {
544
+ throw new TransportError(`CpaasHttpSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {
382
545
  transportName: this.name,
383
546
  cause: err
384
547
  });
@@ -391,17 +554,18 @@ var ZeptoMailHttpSender = class {
391
554
  responseData = { raw: responseText };
392
555
  }
393
556
  if (!response.ok) {
394
- const errorMessage = responseData?.error?.message || responseData?.message || `HTTP ${response.status}: ${responseText || response.statusText}`;
395
- throw new TransportError(`ZeptoMailHttpSender: Failed to send email - ${errorMessage}`, {
557
+ const errorMessage = responseData?.data?.message || responseData?.error?.message || responseData?.message || `HTTP ${response.status}: ${responseText || response.statusText}`;
558
+ throw new TransportError(`CpaasHttpSender: Failed to send email - ${errorMessage}`, {
396
559
  transportName: this.name,
397
560
  statusCode: response.status,
398
- responseBody: responseText
561
+ responseBody: responseText,
562
+ rawResponse: responseData
399
563
  });
400
564
  }
401
565
  return {
402
566
  success: true,
403
567
  messageId: responseData?.data?.[0]?.message_id,
404
- response: responseData
568
+ rawResponse: responseData
405
569
  };
406
570
  }
407
571
  };
@@ -415,36 +579,76 @@ var ZeptoMailHttpSender = class {
415
579
  var MemoryEmailSender = class {
416
580
  name = "memory";
417
581
  sentMails = [];
582
+ sentBulkMails = [];
583
+ sentTemplateMails = [];
584
+ sentBulkTemplateMails = [];
418
585
  nextId = 1;
419
- async send(options) {
420
- this.sentMails.push({ ...options });
421
- const messageId = `mem-${this.nextId++}-${Date.now()}`;
586
+ result(prefix) {
587
+ const id = this.nextId++;
588
+ const messageId = prefix ? `mem-${prefix}-${id}-${Date.now()}` : `mem-${id}-${Date.now()}`;
422
589
  return {
423
590
  success: true,
424
591
  messageId,
425
- response: { id: messageId }
592
+ rawResponse: { id: messageId }
426
593
  };
427
594
  }
595
+ async send(options) {
596
+ this.sentMails.push({ ...options });
597
+ return this.result();
598
+ }
599
+ async sendBulk(options) {
600
+ this.sentBulkMails.push({ ...options });
601
+ return this.result("bulk");
602
+ }
603
+ async sendKnownTemplate(options) {
604
+ this.sentTemplateMails.push({ ...options });
605
+ return this.result("tpl");
606
+ }
607
+ async sendBulkKnownTemplate(options) {
608
+ this.sentBulkTemplateMails.push({ ...options });
609
+ return this.result("bulk-tpl");
610
+ }
428
611
  /**
429
- * Returns a copy of all emails sent through this transport instance.
612
+ * Returns a copy of all single emails sent through this transport instance.
430
613
  */
431
614
  getSentMails() {
432
615
  return [...this.sentMails];
433
616
  }
434
617
  /**
435
- * Returns the most recent email sent, or undefined if no emails have been sent.
618
+ * Returns the most recent single email sent, or undefined if none have been sent.
436
619
  */
437
620
  getLastMail() {
438
621
  return this.sentMails.length > 0 ? { ...this.sentMails[this.sentMails.length - 1] } : void 0;
439
622
  }
440
623
  /**
441
- * Clears all recorded sent emails.
624
+ * Returns a copy of all bulk emails sent through this transport instance.
625
+ */
626
+ getSentBulkMails() {
627
+ return [...this.sentBulkMails];
628
+ }
629
+ /**
630
+ * Returns a copy of all single template emails sent through this transport instance.
631
+ */
632
+ getSentTemplateMails() {
633
+ return [...this.sentTemplateMails];
634
+ }
635
+ /**
636
+ * Returns a copy of all bulk template emails sent through this transport instance.
637
+ */
638
+ getSentBulkTemplateMails() {
639
+ return [...this.sentBulkTemplateMails];
640
+ }
641
+ /**
642
+ * Clears all recorded emails.
442
643
  */
443
644
  clear() {
444
645
  this.sentMails = [];
646
+ this.sentBulkMails = [];
647
+ this.sentTemplateMails = [];
648
+ this.sentBulkTemplateMails = [];
445
649
  }
446
650
  /**
447
- * Returns the total count of sent emails.
651
+ * Returns the total count of single emails sent.
448
652
  */
449
653
  count() {
450
654
  return this.sentMails.length;
@@ -467,33 +671,70 @@ var ConsoleEmailSender = class {
467
671
  this.includeHtml = options.includeHtml ?? false;
468
672
  }
469
673
  async send(options) {
470
- const to = normalizeRecipients(options.to).map((r) => r.name ? `${r.name} <${r.address}>` : r.address).join(", ");
471
- const from = options.from ? JSON.stringify(options.from) : "(default)";
674
+ return this.logDispatch({
675
+ kind: "EMAIL",
676
+ to: options.to,
677
+ from: options.from,
678
+ subject: options.subject,
679
+ text: options.text,
680
+ html: options.html
681
+ });
682
+ }
683
+ async sendBulk(options) {
684
+ return this.logDispatch({
685
+ kind: "BULK EMAIL",
686
+ to: options.to,
687
+ from: options.from,
688
+ subject: options.subject,
689
+ text: options.text,
690
+ html: options.html
691
+ });
692
+ }
693
+ async sendKnownTemplate(options) {
694
+ return this.logDispatch({
695
+ kind: "TEMPLATE EMAIL",
696
+ to: options.to,
697
+ from: options.from,
698
+ templateId: options.templateId
699
+ });
700
+ }
701
+ async sendBulkKnownTemplate(options) {
702
+ return this.logDispatch({
703
+ kind: "BULK TEMPLATE EMAIL",
704
+ to: options.to,
705
+ from: options.from,
706
+ templateId: options.templateId
707
+ });
708
+ }
709
+ logDispatch(entry) {
710
+ const to = normalizeRecipients(entry.to).map((r) => r.name ? `${r.name} <${r.address}>` : r.address).join(", ");
711
+ const from = entry.from ? JSON.stringify(entry.from) : "(default)";
472
712
  const messageId = `console-${this.nextId++}-${Date.now()}`;
473
713
  const separator = "─".repeat(60);
474
714
  const lines = [
475
715
  `\n┌${separator}┐`,
476
- `│ [ts-mailkit:console] DISPATCHED EMAIL (${messageId})`,
716
+ `│ [ts-mailkit:console] DISPATCHED ${entry.kind} (${messageId})`,
477
717
  `├${separator}┤`,
478
718
  `│ From: ${from}`,
479
- `│ To: ${to}`,
480
- `│ Subject: ${options.subject}`,
481
- `├${separator}┤`
719
+ `│ To: ${to}`
482
720
  ];
483
- if (options.text) {
721
+ if (entry.subject !== void 0) lines.push(`│ Subject: ${entry.subject}`);
722
+ if (entry.templateId !== void 0) lines.push(`│ Template: ${entry.templateId}`);
723
+ lines.push(`├${separator}┤`);
724
+ if (entry.text) {
484
725
  lines.push("│ Text Body:");
485
- for (const line of options.text.split("\n")) lines.push(`│ ${line}`);
726
+ for (const line of entry.text.split("\n")) lines.push(`│ ${line}`);
486
727
  }
487
- if (this.includeHtml && options.html) {
728
+ if (this.includeHtml && entry.html) {
488
729
  lines.push("│ HTML Body:");
489
- for (const line of options.html.split("\n")) lines.push(`│ ${line}`);
730
+ for (const line of entry.html.split("\n")) lines.push(`│ ${line}`);
490
731
  }
491
732
  lines.push(`└${separator}┘\n`);
492
733
  this.log(lines.join("\n"));
493
734
  return {
494
735
  success: true,
495
736
  messageId,
496
- response: { logged: true }
737
+ rawResponse: { logged: true }
497
738
  };
498
739
  }
499
740
  };
@@ -680,5 +921,23 @@ var EmailTemplateFactory = class EmailTemplateFactory {
680
921
  };
681
922
 
682
923
  //#endregion
683
- export { ConfigurationError, ConsoleEmailSender, DefaultEmailRenderer, EmailTemplateFactory, MailKit, MailKitError, MemoryEmailSender, TemplateError, TransportError, ZeptoMailHttpSender, buildHtml, buildPlainText, createMailKit, decodeHtmlEntities, htmlToPlainText, isValidHttpUrl, normalizeRecipient, normalizeRecipients, parseEmailAddress };
924
+ //#region src/templates/template-builder.ts
925
+ /**
926
+ * Builds an upload-ready HTML template from the canonical {@link EmailTemplateDto}.
927
+ *
928
+ * The output can be uploaded to a messaging platform (Zoho CPaaS, SendGrid, etc.)
929
+ * as a provider-side template.
930
+ */
931
+ function buildHTMLTemplate(dto, options = {}) {
932
+ return buildHtml(dto, options);
933
+ }
934
+ /**
935
+ * Builds an upload-ready plain-text template from the canonical {@link EmailTemplateDto}.
936
+ */
937
+ function buildPlainTextTemplate(dto, _options) {
938
+ return buildPlainText(dto);
939
+ }
940
+
941
+ //#endregion
942
+ export { ConfigurationError, ConsoleEmailSender, CpaasHttpSender, DefaultEmailRenderer, EmailTemplateFactory, MailKit, MailKitError, MemoryEmailSender, TemplateError, TransportError, buildHTMLTemplate, buildHtml, buildPlainText, buildPlainTextTemplate, createMailKit, decodeHtmlEntities, htmlToPlainText, isValidHttpUrl, normalizeRecipient, normalizeRecipients, parseEmailAddress };
684
943
  //# sourceMappingURL=index.js.map