feat(wire): Add wire protocol, WireTarget & WireParser, Smartmail JSON serialization; refactor plugins and update dependencies
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import * as plugins from './smartmail.plugins.js';
|
||||
import { EmailAddressValidator } from './smartmail.classes.emailaddressvalidator.js';
|
||||
import type { IMailSendResponse } from './smartmail.wire.js';
|
||||
import type { WireTarget } from './smartmail.classes.wiretarget.js';
|
||||
|
||||
export type EmailAddress = string;
|
||||
export type EmailAddressList = EmailAddress[];
|
||||
@@ -19,6 +21,33 @@ export interface ISmartmailOptions<T> {
|
||||
validateEmails?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON representation of an attachment for wire transmission
|
||||
*/
|
||||
export interface IAttachmentJson {
|
||||
filename: string;
|
||||
contentBase64: string;
|
||||
contentType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON representation of a Smartmail for wire transmission
|
||||
*/
|
||||
export interface ISmartmailJson<T = unknown> {
|
||||
from: string;
|
||||
to?: string[];
|
||||
cc?: string[];
|
||||
bcc?: string[];
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
htmlBody?: string;
|
||||
headers?: Record<string, string>;
|
||||
priority?: 'high' | 'normal' | 'low';
|
||||
creationObjectRef?: T;
|
||||
attachments: IAttachmentJson[];
|
||||
}
|
||||
|
||||
export interface IMimeAttachment {
|
||||
filename: string;
|
||||
content: Buffer;
|
||||
@@ -51,9 +80,11 @@ export class Smartmail<T> {
|
||||
/**
|
||||
* Adds an attachment to the email
|
||||
* @param smartfileArg The file to attach
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public addAttachment(smartfileArg: plugins.smartfile.SmartFile) {
|
||||
public addAttachment(smartfileArg: plugins.smartfile.SmartFile): this {
|
||||
this.attachments.push(smartfileArg);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,27 +108,30 @@ export class Smartmail<T> {
|
||||
/**
|
||||
* Applies variables to all template strings in the email
|
||||
* @param variables Variables to apply to templates
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public applyVariables(variables: Record<string, any>): void {
|
||||
public applyVariables(variables: Record<string, any>): this {
|
||||
if (!variables || typeof variables !== 'object') {
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// Process the subject, body, and HTML body with the provided variables
|
||||
if (this.options.subject) {
|
||||
const subjectMustache = new plugins.smartmustache.SmartMustache(this.options.subject);
|
||||
this.options.subject = subjectMustache.applyData(variables);
|
||||
}
|
||||
|
||||
|
||||
if (this.options.body) {
|
||||
const bodyMustache = new plugins.smartmustache.SmartMustache(this.options.body);
|
||||
this.options.body = bodyMustache.applyData(variables);
|
||||
}
|
||||
|
||||
|
||||
if (this.options.htmlBody) {
|
||||
const htmlBodyMustache = new plugins.smartmustache.SmartMustache(this.options.htmlBody);
|
||||
this.options.htmlBody = htmlBodyMustache.applyData(variables);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,55 +162,65 @@ export class Smartmail<T> {
|
||||
* Adds a recipient to the email
|
||||
* @param email Email address to add
|
||||
* @param type Type of recipient (to, cc, bcc)
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public addRecipient(email: EmailAddress, type: 'to' | 'cc' | 'bcc' = 'to'): void {
|
||||
public addRecipient(email: EmailAddress, type: 'to' | 'cc' | 'bcc' = 'to'): this {
|
||||
if (!this.options[type]) {
|
||||
this.options[type] = [];
|
||||
}
|
||||
|
||||
|
||||
this.options[type]!.push(email);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple recipients to the email
|
||||
* @param emails Email addresses to add
|
||||
* @param type Type of recipients (to, cc, bcc)
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public addRecipients(emails: EmailAddressList, type: 'to' | 'cc' | 'bcc' = 'to'): void {
|
||||
public addRecipients(emails: EmailAddressList, type: 'to' | 'cc' | 'bcc' = 'to'): this {
|
||||
if (!this.options[type]) {
|
||||
this.options[type] = [];
|
||||
}
|
||||
|
||||
|
||||
this.options[type] = [...this.options[type]!, ...emails];
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reply-to address
|
||||
* @param email Email address for reply-to
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public setReplyTo(email: EmailAddress): void {
|
||||
public setReplyTo(email: EmailAddress): this {
|
||||
this.options.replyTo = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the priority of the email
|
||||
* @param priority Priority level
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public setPriority(priority: 'high' | 'normal' | 'low'): void {
|
||||
public setPriority(priority: 'high' | 'normal' | 'low'): this {
|
||||
this.options.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom header to the email
|
||||
* @param name Header name
|
||||
* @param value Header value
|
||||
* @returns this for chaining
|
||||
*/
|
||||
public addHeader(name: string, value: string): void {
|
||||
public addHeader(name: string, value: string): this {
|
||||
if (!this.options.headers) {
|
||||
this.options.headers = {};
|
||||
}
|
||||
|
||||
|
||||
this.options.headers[name] = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,6 +247,102 @@ export class Smartmail<T> {
|
||||
return results;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Wire Format Serialization Methods
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* Converts the email to a JSON-serializable object for wire transmission
|
||||
* @returns JSON-serializable object
|
||||
*/
|
||||
public toObject(): ISmartmailJson<T> {
|
||||
const attachmentsJson: IAttachmentJson[] = this.attachments.map((file) => ({
|
||||
filename: file.path.split('/').pop() || 'attachment',
|
||||
contentBase64: file.contentBuffer.toString('base64'),
|
||||
contentType: 'application/octet-stream',
|
||||
}));
|
||||
|
||||
return {
|
||||
from: this.options.from,
|
||||
to: this.options.to,
|
||||
cc: this.options.cc,
|
||||
bcc: this.options.bcc,
|
||||
replyTo: this.options.replyTo,
|
||||
subject: this.options.subject,
|
||||
body: this.options.body,
|
||||
htmlBody: this.options.htmlBody,
|
||||
headers: this.options.headers,
|
||||
priority: this.options.priority,
|
||||
creationObjectRef: this.options.creationObjectRef,
|
||||
attachments: attachmentsJson,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes the email to a JSON string for wire transmission
|
||||
* @returns JSON string
|
||||
*/
|
||||
public toJson(): string {
|
||||
return JSON.stringify(this.toObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Smartmail instance from a JSON-serializable object
|
||||
* @param obj JSON object representing the email
|
||||
* @returns Smartmail instance
|
||||
*/
|
||||
public static fromObject<T = unknown>(obj: ISmartmailJson<T>): Smartmail<T> {
|
||||
const email = new Smartmail<T>({
|
||||
from: obj.from,
|
||||
to: obj.to,
|
||||
cc: obj.cc,
|
||||
bcc: obj.bcc,
|
||||
replyTo: obj.replyTo,
|
||||
subject: obj.subject,
|
||||
body: obj.body,
|
||||
htmlBody: obj.htmlBody,
|
||||
headers: obj.headers,
|
||||
priority: obj.priority,
|
||||
creationObjectRef: obj.creationObjectRef,
|
||||
});
|
||||
|
||||
// Reconstruct attachments from base64
|
||||
for (const att of obj.attachments || []) {
|
||||
const buffer = Buffer.from(att.contentBase64, 'base64');
|
||||
const smartfile = new plugins.smartfile.SmartFile({
|
||||
path: att.filename,
|
||||
contentBuffer: buffer,
|
||||
base: './',
|
||||
});
|
||||
email.attachments.push(smartfile);
|
||||
}
|
||||
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a Smartmail instance from a JSON string
|
||||
* @param json JSON string representing the email
|
||||
* @returns Smartmail instance
|
||||
*/
|
||||
public static fromJson<T = unknown>(json: string): Smartmail<T> {
|
||||
const obj = JSON.parse(json) as ISmartmailJson<T>;
|
||||
return Smartmail.fromObject<T>(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this email to a WireTarget
|
||||
* @param target The WireTarget to send the email to
|
||||
* @returns Promise resolving to the send response
|
||||
*/
|
||||
public async sendTo(target: WireTarget): Promise<IMailSendResponse> {
|
||||
return target.sendEmail(this);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// MIME Format Methods
|
||||
// ==========================================
|
||||
|
||||
/**
|
||||
* Converts the email to a MIME format object for sending
|
||||
* @param dataArg Data to apply to templates
|
||||
|
||||
Reference in New Issue
Block a user