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