ts-mailkit 0.1.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/types.ts","../src/core/errors.ts","../src/renderers/utils/html-to-plaintext.ts","../src/renderers/default/default-renderer.ts","../src/core/client.ts","../src/transports/zeptomail/zeptomail-sender.ts","../src/transports/memory/memory-sender.ts","../src/transports/console/console-sender.ts","../src/templates/factory.ts"],"sourcesContent":["// ─── Core Types, Envelopes & Errors ──────────────────────────────────────────\nexport * from './core/types.js';\nexport * from './core/errors.js';\nexport * from './core/client.js';\n\n// ─── Transport Interface & Implementations ────────────────────────────────────\nexport * from './transports/sender.interface.js';\nexport * from './transports/zeptomail/zeptomail-sender.js';\nexport * from './transports/zeptomail/types.js';\nexport * from './transports/memory/memory-sender.js';\nexport * from './transports/console/console-sender.js';\n\n// ─── Template DTOs & Factory ──────────────────────────────────────────────────\nexport * from './templates/dto/index.js';\nexport * from './templates/factory.js';\n\n// ─── Renderers & Utilities ────────────────────────────────────────────────────\nexport * from './renderers/renderer.interface.js';\nexport * from './renderers/default/default-renderer.js';\nexport * from './renderers/utils/html-to-plaintext.js';\n","/**\n * Standard email address representation with optional display name.\n */\nexport interface EmailAddress {\n address: string;\n name?: string;\n}\n\n/**\n * Flexible recipient representation allowing string ('user@example.com'),\n * EmailAddress ({ address: 'user@example.com', name: 'User' }),\n * or legacy/standard object ({ email: 'user@example.com', name: 'User' }).\n */\nexport type Recipient =\n | string\n | EmailAddress\n | { email: string; name?: string };\n\n/**\n * Normalizes a Recipient value into a standardized EmailAddress.\n */\nexport function normalizeRecipient(recipient: Recipient): EmailAddress {\n if (typeof recipient === 'string') {\n return { address: recipient.trim() };\n }\n if ('email' in recipient) {\n return {\n address: (recipient.email ?? '').trim(),\n name: recipient.name?.trim(),\n };\n }\n return {\n address: (recipient.address ?? '').trim(),\n name: recipient.name?.trim(),\n };\n}\n\n/**\n * Normalizes a single or array of Recipients into an array of EmailAddress.\n */\nexport function normalizeRecipients(\n recipients?: Recipient | Recipient[]\n): EmailAddress[] {\n if (!recipients) return [];\n const list = Array.isArray(recipients) ? recipients : [recipients];\n return list.map(normalizeRecipient).filter((r) => r.address.length > 0);\n}\n\n/**\n * Email attachment representation.\n */\nexport interface EmailAttachment {\n filename: string;\n /**\n * Content can be base64-encoded string, plain text, or binary Buffer/Uint8Array.\n */\n content: string | Uint8Array;\n mimeType?: string;\n contentType?: string;\n cid?: string;\n}\n\n/**\n * Options for sending an email through a transport adapter.\n */\nexport interface SendMailOptions {\n to: Recipient | Recipient[];\n from?: Recipient;\n subject: string;\n html: string;\n text?: string;\n cc?: Recipient | Recipient[];\n bcc?: Recipient | Recipient[];\n replyTo?: Recipient | Recipient[];\n attachments?: EmailAttachment[];\n headers?: Record<string, string>;\n tags?: string[];\n metadata?: Record<string, string>;\n}\n\n/**\n * Result returned by an IEmailSender upon dispatch.\n */\nexport interface SendResult {\n success: boolean;\n messageId?: string;\n response?: unknown;\n}\n","/**\n * Base error class for all ts-mailkit errors.\n */\nexport class MailKitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MailKitError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when transport configuration is missing or invalid.\n */\nexport class ConfigurationError extends MailKitError {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when an email transport fails to dispatch an email.\n */\nexport class TransportError extends MailKitError {\n readonly transportName: string;\n readonly statusCode?: number;\n readonly responseBody?: string;\n readonly cause?: unknown;\n\n constructor(\n message: string,\n options: {\n transportName: string;\n statusCode?: number;\n responseBody?: string;\n cause?: unknown;\n }\n ) {\n super(message);\n this.name = 'TransportError';\n this.transportName = options.transportName;\n this.statusCode = options.statusCode;\n this.responseBody = options.responseBody;\n this.cause = options.cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when template rendering or DTO validation fails.\n */\nexport class TemplateError extends MailKitError {\n constructor(message: string) {\n super(message);\n this.name = 'TemplateError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","/**\n * Decodes common HTML entities into their plain text equivalents.\n */\nexport function decodeHtmlEntities(text: string): string {\n return text\n .replace(/&nbsp;/gi, ' ')\n .replace(/&amp;/gi, '&')\n .replace(/&lt;/gi, '<')\n .replace(/&gt;/gi, '>')\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\")\n .replace(/&copy;/gi, '©')\n .replace(/&reg;/gi, '®')\n .replace(/&trade;/gi, '™');\n}\n\n/**\n * Strips HTML tags and normalizes whitespace into readable plain text.\n * Converts <br>, <p>, and <div> into appropriate line breaks.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return '';\n\n return decodeHtmlEntities(\n html\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<\\/p>/gi, '\\n\\n')\n .replace(/<\\/div>/gi, '\\n')\n .replace(/<\\/h[1-6]>/gi, '\\n\\n')\n .replace(/<[^>]*>/g, '')\n )\n .replace(/[ \\t]+/g, ' ')\n .replace(/\\n\\s*\\n\\s*\\n+/g, '\\n\\n')\n .trim();\n}\n","import type { BaseEmailDto } from '../../templates/dto/index.js';\nimport type { IEmailRenderer, RenderedEmail } from '../renderer.interface.js';\nimport { htmlToPlainText } from '../utils/html-to-plaintext.js';\n\nexport interface DefaultRendererOptions {\n /**\n * Primary brand color for buttons and accents.\n * @default '#4f46e5'\n */\n primaryColor?: string;\n\n /**\n * Font stack used in the HTML wrapper.\n * @default \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\"\n */\n fontFamily?: string;\n\n /**\n * Container maximum width.\n * @default '600px'\n */\n maxWidth?: string;\n}\n\n/**\n * Builds a plain-text fallback string from an email DTO.\n */\nexport function buildPlainText(dto: BaseEmailDto): string {\n if (dto.noHtmlMessage) {\n return dto.noHtmlMessage;\n }\n\n const divider = '──────────────────────────────';\n const parts: string[] = [];\n\n if (dto.header) {\n parts.push(dto.header, divider);\n }\n\n if (dto.body) {\n parts.push(htmlToPlainText(dto.body));\n }\n\n if (dto.otpCode) {\n parts.push(`Verification Code: ${dto.otpCode}`);\n }\n\n if (dto.actionText && dto.actionUrl) {\n parts.push(`${dto.actionText}: ${dto.actionUrl}`);\n }\n\n if (dto.extraMessage) {\n parts.push(htmlToPlainText(dto.extraMessage));\n }\n\n if (dto.footer) {\n parts.push(`${divider}\\n${htmlToPlainText(dto.footer)}`);\n }\n\n return parts.join('\\n\\n');\n}\n\n/**\n * Builds a responsive, styled HTML email document from an email DTO.\n */\nexport function buildHtml(dto: BaseEmailDto, options: DefaultRendererOptions = {}): string {\n const primaryColor = options.primaryColor || '#4f46e5';\n const fontFamily =\n options.fontFamily ||\n \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\";\n const maxWidth = options.maxWidth || '600px';\n\n const parts: string[] = [\n `<!DOCTYPE html>`,\n `<html lang=\"en\">`,\n `<head>`,\n `<meta charset=\"UTF-8\">`,\n `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">`,\n `<title>${dto.subject}</title>`,\n `</head>`,\n `<body style=\"margin:0;padding:24px 16px;background-color:#f9fafb;font-family:${fontFamily};color:#1f2937;line-height:1.6;\">`,\n `<div style=\"max-width:${maxWidth};margin:0 auto;background-color:#ffffff;padding:32px 28px;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.1);border:1px solid #f3f4f6;\">`,\n ];\n\n if (dto.imageUrl) {\n parts.push(\n `<div style=\"margin-bottom:24px;text-align:center;\">`,\n ` <img src=\"${dto.imageUrl}\" alt=\"Header\" style=\"max-width:100%;height:auto;border-radius:6px;\" />`,\n `</div>`\n );\n }\n\n if (dto.header) {\n parts.push(\n `<h2 style=\"margin:0 0 16px;font-size:1.5rem;font-weight:700;color:#111827;letter-spacing:-0.025em;\">${dto.header}</h2>`\n );\n }\n\n if (dto.body) {\n parts.push(`<div style=\"margin:0 0 20px;font-size:1rem;color:#374151;\">${dto.body}</div>`);\n }\n\n if (dto.otpCode) {\n parts.push(\n `<div style=\"margin:24px 0;padding:20px;background-color:#f3f4f6;border-radius:8px;text-align:center;\">`,\n ` <span style=\"font-size:2rem;letter-spacing:0.5rem;font-weight:700;color:#111827;font-family:monospace;\">${dto.otpCode}</span>`,\n `</div>`\n );\n }\n\n if (dto.actionUrl && dto.actionText) {\n parts.push(\n `<div style=\"margin:24px 0;text-align:center;\">`,\n ` <a href=\"${dto.actionUrl}\" style=\"display:inline-block;padding:12px 28px;background-color:${primaryColor};color:#ffffff;border-radius:6px;text-decoration:none;font-weight:600;font-size:1rem;text-align:center;box-sizing:border-box;\">${dto.actionText}</a>`,\n `</div>`\n );\n }\n\n if (dto.extraMessage) {\n parts.push(\n `<div style=\"margin:20px 0 0;font-size:0.875rem;color:#6b7280;line-height:1.5;\">${dto.extraMessage}</div>`\n );\n }\n\n if (dto.footer) {\n parts.push(\n `<div style=\"margin-top:32px;padding-top:20px;border-top:1px solid #e5e7eb;font-size:0.75rem;color:#9ca3af;text-align:center;\">${dto.footer}</div>`\n );\n }\n\n parts.push(`</div>`, `</body>`, `</html>`);\n return parts.join('\\n');\n}\n\n/**\n * Default HTML and plain-text email renderer for ts-mailkit.\n */\nexport class DefaultEmailRenderer implements IEmailRenderer {\n private readonly options: DefaultRendererOptions;\n\n constructor(options: DefaultRendererOptions = {}) {\n this.options = options;\n }\n\n render(dto: BaseEmailDto): RenderedEmail {\n return {\n html: buildHtml(dto, this.options),\n text: buildPlainText(dto),\n };\n }\n}\n","import type { IEmailSender } from '../transports/sender.interface.js';\nimport type { IEmailRenderer, RenderedEmail } from '../renderers/renderer.interface.js';\nimport { DefaultEmailRenderer, buildPlainText } from '../renderers/default/default-renderer.js';\nimport type { BaseEmailDto } from '../templates/dto/index.js';\nimport {\n normalizeRecipient,\n normalizeRecipients,\n type Recipient,\n type SendMailOptions,\n type SendResult,\n} from './types.js';\nimport { ConfigurationError } from './errors.js';\n\nexport interface SendTemplateOptions {\n /**\n * One or more recipient email addresses.\n */\n to: Recipient | Recipient[];\n /**\n * Templated email DTO to render and send.\n */\n template: BaseEmailDto;\n /**\n * Optional recipient display name (used when `to` is a plain string).\n */\n toName?: string;\n /**\n * Optional sender display name override for this specific email.\n */\n fromName?: string;\n /**\n * Optional sender email address override.\n */\n from?: Recipient;\n /**\n * Optional CC recipients.\n */\n cc?: Recipient | Recipient[];\n /**\n * Optional BCC recipients.\n */\n bcc?: Recipient | Recipient[];\n /**\n * Optional Reply-To recipients.\n */\n replyTo?: Recipient | Recipient[];\n /**\n * Optional file attachments.\n */\n attachments?: SendMailOptions['attachments'];\n /**\n * Optional custom headers.\n */\n headers?: Record<string, string>;\n /**\n * Optional tags for tracking.\n */\n tags?: string[];\n /**\n * Optional metadata.\n */\n metadata?: Record<string, string>;\n}\n\nexport interface MailKitOptions {\n /**\n * The transport adapter used to dispatch emails (e.g. ZeptoMailSender, MemoryEmailSender).\n */\n transport: IEmailSender;\n /**\n * Custom renderer implementation. Defaults to DefaultEmailRenderer.\n */\n renderer?: IEmailRenderer;\n /**\n * Default sender address or Recipient.\n */\n defaultFrom?: Recipient;\n /**\n * Default brand or application name.\n */\n defaultBrandName?: string;\n /**\n * Optional asynchronous or synchronous resolver to dynamically resolve brand/tenant name.\n * Useful for multitenant applications.\n */\n brandNameResolver?: () => Promise<string> | string;\n}\n\n/**\n * Main email client and orchestration service for ts-mailkit.\n */\nexport class MailKit {\n private readonly transport: IEmailSender;\n private readonly renderer: IEmailRenderer;\n private readonly defaultFrom?: Recipient;\n private readonly defaultBrandName?: string;\n private readonly brandNameResolver?: () => Promise<string> | string;\n\n constructor(options: MailKitOptions) {\n if (!options.transport) {\n throw new ConfigurationError('MailKit: A transport adapter (IEmailSender) is required.');\n }\n this.transport = options.transport;\n this.renderer = options.renderer ?? new DefaultEmailRenderer();\n this.defaultFrom = options.defaultFrom;\n this.defaultBrandName = options.defaultBrandName;\n this.brandNameResolver = options.brandNameResolver;\n }\n\n /**\n * Returns the underlying transport instance.\n */\n getTransport(): IEmailSender {\n return this.transport;\n }\n\n /**\n * Renders an email DTO to HTML and plain text without dispatching.\n */\n async render(template: BaseEmailDto): Promise<RenderedEmail> {\n return await this.renderer.render(template);\n }\n\n /**\n * Returns the plain-text fallback for an email DTO without sending.\n */\n buildPlainTextMessage(template: BaseEmailDto): string {\n return template.noHtmlMessage ?? buildPlainText(template);\n }\n\n /**\n * Sends an email using a strongly-typed template DTO.\n * Supports both modern options object:\n * `mailer.send({ to: 'user@example.com', template: myDto })`\n * and legacy positional arguments for seamless migration:\n * `mailer.send('user@example.com', myDto, 'User Name')`\n */\n async send(options: SendTemplateOptions): Promise<SendResult>;\n async send(to: string, template: BaseEmailDto, toName?: string): Promise<SendResult>;\n async send(\n optionsOrTo: SendTemplateOptions | string,\n maybeTemplate?: BaseEmailDto,\n maybeToName?: string\n ): Promise<SendResult> {\n let opts: SendTemplateOptions;\n\n if (typeof optionsOrTo === 'string') {\n if (!maybeTemplate) {\n throw new ConfigurationError('MailKit.send: Missing required template DTO argument.');\n }\n opts = {\n to: optionsOrTo,\n template: maybeTemplate,\n toName: maybeToName,\n };\n } else {\n opts = optionsOrTo;\n }\n\n const template = opts.template;\n const recipientName = opts.toName ?? template.userName;\n\n // Resolve fromName: explicit option > template.fromName > brand resolver > defaultBrandName\n let resolvedFromName = opts.fromName ?? template.fromName;\n if (!resolvedFromName && this.brandNameResolver) {\n resolvedFromName = await this.brandNameResolver();\n }\n if (!resolvedFromName) {\n resolvedFromName = this.defaultBrandName;\n }\n\n // Render template DTO\n const rendered = await this.renderer.render(template);\n const plaintextBody = template.noHtmlMessage ?? rendered.text;\n\n // Format recipients\n let toRecipients: Recipient | Recipient[];\n if (typeof opts.to === 'string' && recipientName) {\n toRecipients = { address: opts.to, name: recipientName };\n } else {\n toRecipients = opts.to;\n }\n\n // Resolve From address\n let from = opts.from ?? this.defaultFrom;\n if (resolvedFromName && from) {\n const normalizedFrom = normalizeRecipient(from);\n from = { address: normalizedFrom.address, name: resolvedFromName };\n }\n\n return await this.sendRaw({\n to: toRecipients,\n from,\n subject: template.subject,\n html: rendered.html,\n text: plaintextBody,\n cc: opts.cc,\n bcc: opts.bcc,\n replyTo: opts.replyTo,\n attachments: opts.attachments,\n headers: opts.headers,\n tags: opts.tags,\n metadata: opts.metadata,\n });\n }\n\n /**\n * Dispatches a raw, pre-rendered email directly through the transport.\n */\n async sendRaw(options: SendMailOptions): Promise<SendResult> {\n const from = options.from ?? this.defaultFrom;\n return await this.transport.send({\n ...options,\n from,\n });\n }\n\n /**\n * Sends a raw plain-text email with basic HTML pre-formatting.\n * Useful for plain notifications, alerts, or simple text messages.\n */\n async sendSimpleMessage(\n to: string,\n subject: string,\n text: string,\n toName: string = ''\n ): Promise<SendResult> {\n const html = `<pre style=\"font-family:monospace;white-space:pre-wrap;\">${text}</pre>`;\n return await this.sendRaw({\n to: { address: to, name: toName },\n subject,\n html,\n text,\n });\n }\n}\n\n/**\n * Drop-in alias for MailKit to maintain compatibility with existing EmailService code.\n */\nexport const EmailService = MailKit;\nexport type EmailService = MailKit;\n\n/**\n * Convenience factory to create a MailKit client instance.\n */\nexport function createMailKit(options: MailKitOptions): MailKit {\n return new MailKit(options);\n}\n","import { ConfigurationError, TransportError } from '../../core/errors.js';\nimport {\n normalizeRecipient,\n normalizeRecipients,\n type SendMailOptions,\n type SendResult,\n} from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\nimport type {\n ZeptoMailConfig,\n ZeptoMailSendPayload,\n ZeptoMailAttachmentPayload,\n} from './types.js';\n\n/**\n * ZeptoMail (Zoho Mail transactional email API) transport adapter.\n *\n * Designed for zero dependencies and universal edge compatibility (Node.js, Bun, Deno, Cloudflare Workers)\n * by utilizing the standard global `fetch` API.\n */\nexport class ZeptoMailSender implements IEmailSender {\n readonly name = 'zeptomail';\n\n private readonly apiUrl: string;\n private readonly authHeader: string;\n private readonly defaultFrom: { address: string; name?: string };\n private readonly fetchImpl: typeof fetch;\n\n constructor(config: ZeptoMailConfig) {\n if (!config.apiToken || typeof config.apiToken !== 'string') {\n throw new ConfigurationError('ZeptoMailSender: Missing or invalid apiToken.');\n }\n if (!config.from) {\n throw new ConfigurationError('ZeptoMailSender: Missing required default from address.');\n }\n\n const host = (config.apiHost || 'api.zeptomail.com').replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n this.apiUrl = `https://${host}/v1.1/email`;\n\n // Normalize auth token header. In ZeptoMail, if the user already included \"Zoho-enczapikey \", use as is; otherwise format standard header.\n const token = config.apiToken.trim();\n this.authHeader = token.startsWith('Zoho-') ? token : `Zoho-enczapikey ${token}`;\n\n this.defaultFrom = normalizeRecipient(config.from);\n if (!this.defaultFrom.address) {\n throw new ConfigurationError('ZeptoMailSender: Configured from address must not be empty.');\n }\n\n this.fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof this.fetchImpl !== 'function') {\n throw new ConfigurationError(\n 'ZeptoMailSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailConfig if running on Node < 18.'\n );\n }\n }\n\n /**\n * Dispatches an email using Zoho ZeptoMail API v1.1.\n */\n async send(options: SendMailOptions): Promise<SendResult> {\n const toRecipients = normalizeRecipients(options.to);\n if (toRecipients.length === 0) {\n throw new TransportError('ZeptoMailSender: At least one recipient (to) must be specified.', {\n transportName: this.name,\n });\n }\n\n const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;\n\n const payload: ZeptoMailSendPayload = {\n from: {\n address: resolvedFrom.address,\n name: resolvedFrom.name,\n },\n to: toRecipients.map((r) => ({\n email_address: {\n address: r.address,\n name: r.name || '',\n },\n })),\n subject: options.subject,\n htmlbody: options.html,\n textbody: options.text,\n };\n\n if (options.cc) {\n const ccList = normalizeRecipients(options.cc);\n if (ccList.length > 0) {\n payload.cc = ccList.map((r) => ({\n email_address: { address: r.address, name: r.name || '' },\n }));\n }\n }\n\n if (options.bcc) {\n const bccList = normalizeRecipients(options.bcc);\n if (bccList.length > 0) {\n payload.bcc = bccList.map((r) => ({\n email_address: { address: r.address, name: r.name || '' },\n }));\n }\n }\n\n if (options.replyTo) {\n const replyToList = normalizeRecipients(options.replyTo);\n if (replyToList.length > 0) {\n payload.reply_to = replyToList.map((r) => ({\n address: r.address,\n name: r.name,\n }));\n }\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload.attachments = options.attachments.map((att): ZeptoMailAttachmentPayload => {\n let contentBase64: string;\n if (typeof att.content === 'string') {\n contentBase64 = att.content;\n } else {\n // Buffer or Uint8Array\n if (typeof Buffer !== 'undefined') {\n contentBase64 = Buffer.from(att.content).toString('base64');\n } else {\n // Browser / Edge fallback for Uint8Array\n let binary = '';\n const bytes = new Uint8Array(att.content);\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n contentBase64 = btoa(binary);\n }\n }\n\n return {\n name: att.filename,\n content: contentBase64,\n mime_type: att.mimeType || att.contentType || 'application/octet-stream',\n cid: att.cid,\n };\n });\n }\n\n let response: Response;\n try {\n response = await this.fetchImpl(this.apiUrl, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n Authorization: this.authHeader,\n },\n body: JSON.stringify(payload),\n });\n } catch (err) {\n throw new TransportError(`ZeptoMailSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {\n transportName: this.name,\n cause: err,\n });\n }\n\n const responseText = await response.text();\n let responseData: any;\n try {\n responseData = responseText ? JSON.parse(responseText) : {};\n } catch {\n responseData = { raw: responseText };\n }\n\n if (!response.ok) {\n const errorMessage =\n responseData?.error?.message ||\n responseData?.message ||\n `HTTP ${response.status}: ${responseText || response.statusText}`;\n\n throw new TransportError(`ZeptoMailSender: Failed to send email - ${errorMessage}`, {\n transportName: this.name,\n statusCode: response.status,\n responseBody: responseText,\n });\n }\n\n // Extract message ID from standard ZeptoMail v1.1 response structure:\n // { data: [ { message_id: \"...\" } ] }\n const messageId = responseData?.data?.[0]?.message_id;\n\n return {\n success: true,\n messageId,\n response: responseData,\n };\n }\n\n /**\n * Backward-compatible helper method matching legacy signature:\n * `sendEmail(to, htmlBody, subject, toName?, plaintextBody?, fromName?)`\n */\n async sendEmail(\n to: string,\n htmlBody: string,\n subject: string,\n toName: string = '',\n plaintextBody?: string,\n fromName?: string\n ): Promise<void> {\n await this.send({\n to: { address: to, name: toName },\n from: fromName ? { address: this.defaultFrom.address, name: fromName } : this.defaultFrom,\n subject,\n html: htmlBody,\n text: plaintextBody,\n });\n }\n}\n","import type { SendMailOptions, SendResult } from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\n\n/**\n * In-memory email sender for automated testing, local development, and CI environments.\n * Captures all dispatched emails and provides inspection methods.\n */\nexport class MemoryEmailSender implements IEmailSender {\n readonly name = 'memory';\n\n private sentMails: SendMailOptions[] = [];\n private nextId = 1;\n\n async send(options: SendMailOptions): Promise<SendResult> {\n this.sentMails.push({ ...options });\n const messageId = `mem-${this.nextId++}-${Date.now()}`;\n return {\n success: true,\n messageId,\n response: { id: messageId },\n };\n }\n\n /**\n * Returns a copy of all emails sent through this transport instance.\n */\n getSentMails(): SendMailOptions[] {\n return [...this.sentMails];\n }\n\n /**\n * Returns the most recent email sent, or undefined if no emails have been sent.\n */\n getLastMail(): SendMailOptions | undefined {\n return this.sentMails.length > 0\n ? { ...this.sentMails[this.sentMails.length - 1] }\n : undefined;\n }\n\n /**\n * Clears all recorded sent emails.\n */\n clear(): void {\n this.sentMails = [];\n }\n\n /**\n * Returns the total count of sent emails.\n */\n count(): number {\n return this.sentMails.length;\n }\n}\n","import { normalizeRecipients, type SendMailOptions, type SendResult } from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\n\nexport interface ConsoleEmailSenderOptions {\n /**\n * Log level or custom log printer. Defaults to `console.log`.\n */\n logger?: (message: string) => void;\n /**\n * Whether to include the full HTML body in console output.\n * Defaults to false (prints plain text or a summary).\n */\n includeHtml?: boolean;\n}\n\n/**\n * Console logger transport that prints dispatched emails to stdout/stderr.\n * Ideal for development and debugging.\n */\nexport class ConsoleEmailSender implements IEmailSender {\n readonly name = 'console';\n\n private readonly log: (message: string) => void;\n private readonly includeHtml: boolean;\n private nextId = 1;\n\n constructor(options: ConsoleEmailSenderOptions = {}) {\n this.log = options.logger ?? console.log;\n this.includeHtml = options.includeHtml ?? false;\n }\n\n async send(options: SendMailOptions): Promise<SendResult> {\n const to = normalizeRecipients(options.to).map((r) => r.name ? `${r.name} <${r.address}>` : r.address).join(', ');\n const from = options.from ? JSON.stringify(options.from) : '(default)';\n const messageId = `console-${this.nextId++}-${Date.now()}`;\n\n const separator = '─'.repeat(60);\n const lines = [\n `\\n┌${separator}┐`,\n `│ [ts-mailkit:console] DISPATCHED EMAIL (${messageId})`,\n `├${separator}┤`,\n `│ From: ${from}`,\n `│ To: ${to}`,\n `│ Subject: ${options.subject}`,\n `├${separator}┤`,\n ];\n\n if (options.text) {\n lines.push('│ Text Body:');\n for (const line of options.text.split('\\n')) {\n lines.push(`│ ${line}`);\n }\n }\n\n if (this.includeHtml && options.html) {\n lines.push('│ HTML Body:');\n for (const line of options.html.split('\\n')) {\n lines.push(`│ ${line}`);\n }\n }\n\n lines.push(`└${separator}┘\\n`);\n\n this.log(lines.join('\\n'));\n\n return {\n success: true,\n messageId,\n response: { logged: true },\n };\n }\n}\n","import type { BaseEmailDto, EmailTemplateDto } from './dto/index.js';\nimport { htmlToPlainText } from '../renderers/utils/html-to-plaintext.js';\n\nexport interface BrandingConfig {\n /**\n * Default brand, application, or company name.\n * @default 'Application'\n */\n brandName?: string;\n\n /**\n * Optional custom security / disclaimer advisory message.\n */\n securityMessage?: string;\n\n /**\n * Optional custom footer generator or string.\n */\n footer?: string | ((brandName: string) => string);\n}\n\nconst DEFAULT_SECURITY_MESSAGE =\n 'If you did not request this, please ignore this email or contact support if you have concerns.';\n\nfunction defaultFooter(brandName: string): string {\n return `&copy; ${new Date().getFullYear()} ${brandName}. All rights reserved.`;\n}\n\n/**\n * Factory for creating pre-populated, type-safe email template DTOs.\n */\nexport class EmailTemplateFactory {\n private readonly defaultBrandName: string;\n private readonly defaultSecurityMessage: string;\n private readonly footerResolver: (brandName: string) => string;\n\n constructor(config: BrandingConfig = {}) {\n this.defaultBrandName = config.brandName || 'Application';\n this.defaultSecurityMessage = config.securityMessage || DEFAULT_SECURITY_MESSAGE;\n if (typeof config.footer === 'function') {\n this.footerResolver = config.footer;\n } else if (typeof config.footer === 'string') {\n const fixedFooter = config.footer;\n this.footerResolver = () => fixedFooter;\n } else {\n this.footerResolver = defaultFooter;\n }\n }\n\n private resolveBrand(override?: string): string {\n return override || this.defaultBrandName;\n }\n\n private buildFooter(brandName: string): string {\n return this.footerResolver(brandName);\n }\n\n /**\n * Welcome / email-verification email sent after registration.\n */\n createEmailVerification(\n username: string,\n verificationUrl: string,\n otp: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Thank you for signing up. Use the code below or click the button to verify your email address.`;\n return {\n subject: 'Verify Your Email Address',\n header: `Welcome to ${brand}!`,\n body,\n otpCode: otp,\n actionUrl: verificationUrl,\n actionText: 'Verify Email',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage:\n htmlToPlainText(body) +\n `\\n\\nYour verification code is: ${otp}\\n\\nAlternatively, verify here:\\n${verificationUrl}`,\n };\n }\n\n /**\n * Password-reset email with an optional OTP code and action link.\n */\n createPasswordReset(\n username: string,\n resetUrl: string,\n otp: string = '',\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>We received a request to reset your password. Use the OTP code below or click the button to proceed.`;\n const plainTextOtp = otp ? `\\n\\nYour OTP code is: ${otp}` : '';\n return {\n subject: 'Password Reset Request',\n header: 'Reset Your Password',\n body,\n otpCode: otp || undefined,\n actionUrl: resetUrl,\n actionText: 'Reset Password',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage:\n htmlToPlainText(body) +\n plainTextOtp +\n `\\n\\nAlternatively, you can use the following link to reset your password:\\n${resetUrl}`,\n };\n }\n\n /**\n * Generic plain message email (no action button, no OTP).\n */\n createSimpleMessage(\n subject: string,\n header: string,\n body: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n return {\n subject,\n header,\n body,\n footer: this.buildFooter(brand),\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body),\n };\n }\n\n /**\n * Newsletter / announcement email with an optional hero image and CTA button.\n */\n createNewsLetter(\n subject: string,\n header: string,\n body: string,\n imageUrl?: string,\n actionUrl?: string,\n actionText?: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n let noHtmlMessage = htmlToPlainText(body);\n if (actionUrl) {\n noHtmlMessage += `\\n\\n${actionText || 'Learn more'}: ${actionUrl}`;\n }\n return {\n subject,\n header,\n body,\n imageUrl,\n actionUrl,\n actionText,\n footer: this.buildFooter(brand),\n fromName: brand,\n noHtmlMessage,\n };\n }\n\n /**\n * Two-factor authentication email with OTP code and optional magic link.\n */\n create2FAEmail(\n username: string,\n otp: string,\n magicLink: string = '',\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Use the code below or click the button to complete your login.`;\n const plainLink = magicLink ? `\\n\\nAlternatively, verify here:\\n${magicLink}` : '';\n return {\n subject: 'Your Login Verification Code',\n header: 'Two-Factor Authentication',\n body,\n otpCode: otp,\n actionUrl: magicLink || undefined,\n actionText: magicLink ? 'Verify Login' : undefined,\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body) + `\\n\\nYour verification code is: ${otp}` + plainLink,\n };\n }\n\n /**\n * Magic link sign-in email (no OTP, button only).\n */\n createMagicLinkEmail(\n username: string,\n magicLink: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Click the button below to sign in. No password needed.`;\n return {\n subject: 'Your Magic Link',\n header: `Sign In to ${brand}`,\n body,\n actionUrl: magicLink,\n actionText: 'Sign In',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body) + `\\n\\nSign in here:\\n${magicLink}`,\n };\n }\n\n // ─── Default Static Instance ──────────────────────────────────────────────\n private static _defaultInstance?: EmailTemplateFactory;\n\n private static get defaultInstance(): EmailTemplateFactory {\n if (!this._defaultInstance) {\n this._defaultInstance = new EmailTemplateFactory();\n }\n return this._defaultInstance;\n }\n\n static createEmailVerification(\n username: string,\n verificationUrl: string,\n otp: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createEmailVerification(username, verificationUrl, otp, brandName);\n }\n\n static createPasswordReset(\n username: string,\n resetUrl: string,\n otp?: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createPasswordReset(username, resetUrl, otp, brandName);\n }\n\n static createSimpleMessage(\n subject: string,\n header: string,\n body: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createSimpleMessage(subject, header, body, brandName);\n }\n\n static createNewsLetter(\n subject: string,\n header: string,\n body: string,\n imageUrl?: string,\n actionUrl?: string,\n actionText?: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createNewsLetter(\n subject,\n header,\n body,\n imageUrl,\n actionUrl,\n actionText,\n brandName\n );\n }\n\n static create2FAEmail(\n username: string,\n otp: string,\n magicLink?: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.create2FAEmail(username, otp, magicLink, brandName);\n }\n\n static createMagicLinkEmail(\n username: string,\n magicLink: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createMagicLinkEmail(username, magicLink, brandName);\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/types.ts","../src/core/errors.ts","../src/renderers/utils/html-to-plaintext.ts","../src/renderers/default/default-renderer.ts","../src/core/client.ts","../src/transports/zeptomail/zeptomail-sender.ts","../src/transports/memory/memory-sender.ts","../src/transports/console/console-sender.ts","../src/templates/factory.ts"],"sourcesContent":["// ─── Core Types, Envelopes & Errors ──────────────────────────────────────────\nexport * from './core/types.js';\nexport * from './core/errors.js';\nexport * from './core/client.js';\n\n// ─── Transport Interface & Implementations ────────────────────────────────────\nexport * from './transports/sender.interface.js';\nexport * from './transports/zeptomail/zeptomail-sender.js';\nexport * from './transports/zeptomail/types.js';\nexport * from './transports/memory/memory-sender.js';\nexport * from './transports/console/console-sender.js';\n\n// ─── Template DTOs & Factory ──────────────────────────────────────────────────\nexport * from './templates/dto/index.js';\nexport * from './templates/factory.js';\n\n// ─── Renderers & Utilities ────────────────────────────────────────────────────\nexport * from './renderers/renderer.interface.js';\nexport * from './renderers/default/default-renderer.js';\nexport * from './renderers/utils/html-to-plaintext.js';\n","/**\n * Standard email address representation with optional display name.\n */\nexport interface EmailAddress {\n address: string;\n name?: string;\n}\n\n/**\n * Flexible recipient representation allowing string ('user@example.com'),\n * EmailAddress ({ address: 'user@example.com', name: 'User' }),\n * or legacy/standard object ({ email: 'user@example.com', name: 'User' }).\n */\nexport type Recipient =\n | string\n | EmailAddress\n | { email: string; name?: string };\n\n/**\n * Parses an RFC 5322 formatted address string into an EmailAddress.\n * Supports formats such as:\n * - \"user@example.com\" -> { address: \"user@example.com\" }\n * - \"Sender Name <sender@example.com>\" -> { name: \"Sender Name\", address: \"sender@example.com\" }\n * - \"\\\"Sender Name\\\" <sender@example.com>\" -> { name: \"Sender Name\", address: \"sender@example.com\" }\n */\nexport function parseEmailAddress(input: string): EmailAddress {\n if (!input || typeof input !== 'string') {\n return { address: '' };\n }\n const trimmed = input.trim();\n const match = trimmed.match(/^(?:[\"']?([^\"']+)[\"']?\\s+)?<?([^\\s<>@]+@[^\\s<>@]+)>?$/);\n if (!match) {\n return { address: trimmed };\n }\n return {\n address: match[2].trim(),\n name: match[1]?.trim() || undefined,\n };\n}\n\n/**\n * Normalizes a Recipient value into a standardized EmailAddress.\n */\nexport function normalizeRecipient(recipient: Recipient): EmailAddress {\n if (typeof recipient === 'string') {\n return { address: recipient.trim() };\n }\n if ('email' in recipient) {\n return {\n address: (recipient.email ?? '').trim(),\n name: recipient.name?.trim(),\n };\n }\n return {\n address: (recipient.address ?? '').trim(),\n name: recipient.name?.trim(),\n };\n}\n\n/**\n * Normalizes a single or array of Recipients into an array of EmailAddress.\n */\nexport function normalizeRecipients(\n recipients?: Recipient | Recipient[]\n): EmailAddress[] {\n if (!recipients) return [];\n const list = Array.isArray(recipients) ? recipients : [recipients];\n return list.map(normalizeRecipient).filter((r) => r.address.length > 0);\n}\n\n/**\n * Email attachment representation.\n */\nexport interface EmailAttachment {\n filename: string;\n /**\n * Content can be base64-encoded string, plain text, or binary Buffer/Uint8Array.\n */\n content: string | Uint8Array;\n mimeType?: string;\n contentType?: string;\n cid?: string;\n}\n\n/**\n * Options for sending an email through a transport adapter.\n */\nexport interface SendMailOptions {\n to: Recipient | Recipient[];\n from?: Recipient;\n subject: string;\n html: string;\n text?: string;\n cc?: Recipient | Recipient[];\n bcc?: Recipient | Recipient[];\n replyTo?: Recipient | Recipient[];\n attachments?: EmailAttachment[];\n headers?: Record<string, string>;\n tags?: string[];\n metadata?: Record<string, string>;\n}\n\n/**\n * Result returned by an IEmailSender upon dispatch.\n */\nexport interface SendResult {\n success: boolean;\n messageId?: string;\n response?: unknown;\n}\n","/**\n * Base error class for all ts-mailkit errors.\n */\nexport class MailKitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MailKitError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when transport configuration is missing or invalid.\n */\nexport class ConfigurationError extends MailKitError {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when an email transport fails to dispatch an email.\n */\nexport class TransportError extends MailKitError {\n readonly transportName: string;\n readonly statusCode?: number;\n readonly responseBody?: string;\n readonly cause?: unknown;\n\n constructor(\n message: string,\n options: {\n transportName: string;\n statusCode?: number;\n responseBody?: string;\n cause?: unknown;\n }\n ) {\n super(message);\n this.name = 'TransportError';\n this.transportName = options.transportName;\n this.statusCode = options.statusCode;\n this.responseBody = options.responseBody;\n this.cause = options.cause;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown when template rendering or DTO validation fails.\n */\nexport class TemplateError extends MailKitError {\n constructor(message: string) {\n super(message);\n this.name = 'TemplateError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","/**\n * Decodes common HTML entities into their plain text equivalents.\n */\nexport function decodeHtmlEntities(text: string): string {\n return text\n .replace(/&nbsp;/gi, ' ')\n .replace(/&amp;/gi, '&')\n .replace(/&lt;/gi, '<')\n .replace(/&gt;/gi, '>')\n .replace(/&quot;/gi, '\"')\n .replace(/&#39;/gi, \"'\")\n .replace(/&copy;/gi, '©')\n .replace(/&reg;/gi, '®')\n .replace(/&trade;/gi, '™');\n}\n\n/**\n * Strips HTML tags and normalizes whitespace into readable plain text.\n * Converts <br>, <p>, and <div> into appropriate line breaks.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return '';\n\n return decodeHtmlEntities(\n html\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<\\/p>/gi, '\\n\\n')\n .replace(/<\\/div>/gi, '\\n')\n .replace(/<\\/h[1-6]>/gi, '\\n\\n')\n .replace(/<[^>]*>/g, '')\n )\n .replace(/[ \\t]+/g, ' ')\n .replace(/\\n\\s*\\n\\s*\\n+/g, '\\n\\n')\n .trim();\n}\n","import type { EmailTemplateDto } from '../../templates/dto/index.js';\nimport type { IEmailRenderer, RenderedEmail } from '../renderer.interface.js';\nimport { htmlToPlainText } from '../utils/html-to-plaintext.js';\n\nexport interface DefaultRendererOptions {\n /**\n * Primary brand color for buttons and accents.\n * @default '#4f46e5'\n */\n primaryColor?: string;\n\n /**\n * Font stack used in the HTML wrapper.\n * @default \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\"\n */\n fontFamily?: string;\n\n /**\n * Container maximum width.\n * @default '600px'\n */\n maxWidth?: string;\n\n /**\n * Default logo URL displayed at the top-center of the email if not provided in the DTO.\n * Must be a valid http(s) URL.\n */\n logoUrl?: string;\n}\n\n/**\n * Validates whether a string is a valid HTTP or HTTPS URL.\n */\nexport function isValidHttpUrl(urlString?: string): boolean {\n if (!urlString || typeof urlString !== 'string') return false;\n try {\n const url = new URL(urlString.trim());\n return (url.protocol === 'http:' || url.protocol === 'https:') && url.hostname.length > 0;\n } catch {\n return false;\n }\n}\n\n/**\n * Builds a plain-text fallback string from an email DTO.\n */\nexport function buildPlainText(dto: EmailTemplateDto): string {\n if (dto.noHtmlMessage) {\n return dto.noHtmlMessage;\n }\n\n const divider = '──────────────────────────────';\n const parts: string[] = [];\n\n if (dto.header) {\n parts.push(dto.header, divider);\n }\n\n if (dto.body) {\n parts.push(htmlToPlainText(dto.body));\n }\n\n if (dto.otpCode) {\n parts.push(`Verification Code: ${dto.otpCode}`);\n }\n\n if (dto.actionText && dto.actionUrl) {\n parts.push(`${dto.actionText}: ${dto.actionUrl}`);\n }\n\n if (dto.extraMessage) {\n parts.push(htmlToPlainText(dto.extraMessage));\n }\n\n if (dto.footer) {\n parts.push(`${divider}\\n${htmlToPlainText(dto.footer)}`);\n }\n\n return parts.join('\\n\\n');\n}\n\n/**\n * Builds a responsive, styled HTML email document from an email DTO.\n */\nexport function buildHtml(dto: EmailTemplateDto, options: DefaultRendererOptions = {}): string {\n const primaryColor = options.primaryColor || '#4f46e5';\n const fontFamily =\n options.fontFamily ||\n \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\";\n const maxWidth = options.maxWidth || '600px';\n\n const parts: string[] = [\n `<!DOCTYPE html>`,\n `<html lang=\"en\">`,\n `<head>`,\n `<meta charset=\"UTF-8\">`,\n `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">`,\n `<title>${dto.subject}</title>`,\n `</head>`,\n `<body style=\"margin:0;padding:24px 16px;background-color:#f9fafb;font-family:${fontFamily};color:#1f2937;line-height:1.6;\">`,\n `<div style=\"max-width:${maxWidth};margin:0 auto;background-color:#ffffff;padding:32px 28px;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.1);border:1px solid #f3f4f6;\">`,\n ];\n\n const logoCandidate = dto.logoUrl ?? options.logoUrl;\n if (logoCandidate && isValidHttpUrl(logoCandidate)) {\n const validLogo = logoCandidate.trim();\n parts.push(\n `<div style=\"margin-bottom:24px;text-align:center;\">`,\n ` <img src=\"${validLogo}\" alt=\"${dto.fromName || 'Logo'}\" style=\"max-height:48px;max-width:200px;height:auto;width:auto;display:inline-block;border:0;outline:none;text-decoration:none;\" />`,\n `</div>`\n );\n }\n\n if (dto.imageUrl) {\n parts.push(\n `<div style=\"margin-bottom:24px;text-align:center;\">`,\n ` <img src=\"${dto.imageUrl}\" alt=\"Header\" style=\"max-width:100%;height:auto;border-radius:6px;\" />`,\n `</div>`\n );\n }\n\n if (dto.header) {\n parts.push(\n `<h2 style=\"margin:0 0 16px;font-size:1.5rem;font-weight:700;color:#111827;letter-spacing:-0.025em;\">${dto.header}</h2>`\n );\n }\n\n if (dto.body) {\n parts.push(`<div style=\"margin:0 0 20px;font-size:1rem;color:#374151;\">${dto.body}</div>`);\n }\n\n if (dto.otpCode) {\n parts.push(\n `<div style=\"margin:24px 0;padding:20px;background-color:#f3f4f6;border-radius:8px;text-align:center;\">`,\n ` <span style=\"font-size:2rem;letter-spacing:0.5rem;font-weight:700;color:#111827;font-family:monospace;\">${dto.otpCode}</span>`,\n `</div>`\n );\n }\n\n if (dto.actionUrl && dto.actionText) {\n parts.push(\n `<div style=\"margin:24px 0;text-align:center;\">`,\n ` <a href=\"${dto.actionUrl}\" style=\"display:inline-block;padding:12px 28px;background-color:${primaryColor};color:#ffffff;border-radius:6px;text-decoration:none;font-weight:600;font-size:1rem;text-align:center;box-sizing:border-box;\">${dto.actionText}</a>`,\n `</div>`\n );\n }\n\n if (dto.extraMessage) {\n parts.push(\n `<div style=\"margin:20px 0 0;font-size:0.875rem;color:#6b7280;line-height:1.5;\">${dto.extraMessage}</div>`\n );\n }\n\n if (dto.footer) {\n parts.push(\n `<div style=\"margin-top:32px;padding-top:20px;border-top:1px solid #e5e7eb;font-size:0.75rem;color:#9ca3af;text-align:center;\">${dto.footer}</div>`\n );\n }\n\n parts.push(`</div>`, `</body>`, `</html>`);\n return parts.join('\\n');\n}\n\n/**\n * Default HTML and plain-text email renderer for ts-mailkit.\n */\nexport class DefaultEmailRenderer implements IEmailRenderer {\n private readonly options: DefaultRendererOptions;\n\n constructor(options: DefaultRendererOptions = {}) {\n this.options = options;\n }\n\n render(dto: EmailTemplateDto): RenderedEmail {\n return {\n html: buildHtml(dto, this.options),\n text: buildPlainText(dto),\n };\n }\n}\n","import type { IEmailSender } from '../transports/sender.interface.js';\nimport type { IEmailRenderer, RenderedEmail } from '../renderers/renderer.interface.js';\nimport { DefaultEmailRenderer, buildPlainText } from '../renderers/default/default-renderer.js';\nimport { htmlToPlainText } from '../renderers/utils/html-to-plaintext.js';\nimport type { EmailTemplateDto } from '../templates/dto/index.js';\nimport {\n normalizeRecipient,\n normalizeRecipients,\n type Recipient,\n type SendMailOptions,\n type SendResult,\n} from './types.js';\nimport { ConfigurationError } from './errors.js';\n\nexport interface SendTemplateOptions {\n /**\n * One or more recipient email addresses.\n */\n to: Recipient | Recipient[];\n /**\n * Templated email DTO to render and send.\n */\n template: EmailTemplateDto;\n /**\n * Optional recipient display name (used when `to` is a plain string).\n */\n toName?: string;\n /**\n * Optional sender display name override for this specific email.\n */\n fromName?: string;\n /**\n * Optional sender email address override.\n */\n from?: Recipient;\n /**\n * Optional CC recipients.\n */\n cc?: Recipient | Recipient[];\n /**\n * Optional BCC recipients.\n */\n bcc?: Recipient | Recipient[];\n /**\n * Optional Reply-To recipients.\n */\n replyTo?: Recipient | Recipient[];\n /**\n * Optional file attachments.\n */\n attachments?: SendMailOptions['attachments'];\n /**\n * Optional custom headers.\n */\n headers?: Record<string, string>;\n /**\n * Optional tags for tracking.\n */\n tags?: string[];\n /**\n * Optional metadata.\n */\n metadata?: Record<string, string>;\n}\n\nexport interface MailKitOptions {\n /**\n * The transport adapter used to dispatch emails (e.g. ZeptoMailHttpSender, MemoryEmailSender).\n */\n transport: IEmailSender;\n /**\n * Custom renderer implementation. Defaults to DefaultEmailRenderer.\n */\n renderer?: IEmailRenderer;\n /**\n * Default sender address or Recipient.\n */\n defaultFrom?: Recipient;\n /**\n * Default brand or application name.\n */\n defaultBrandName?: string;\n /**\n * Optional asynchronous or synchronous resolver to dynamically resolve brand/tenant name.\n * Useful for multitenant applications.\n */\n brandNameResolver?: () => Promise<string> | string;\n}\n\n/**\n * Main email client and orchestration service for ts-mailkit.\n */\nexport class MailKit {\n private readonly transport: IEmailSender;\n private readonly renderer: IEmailRenderer;\n private readonly defaultFrom?: Recipient;\n private readonly defaultBrandName?: string;\n private readonly brandNameResolver?: () => Promise<string> | string;\n\n constructor(options: MailKitOptions) {\n if (!options.transport) {\n throw new ConfigurationError('MailKit: A transport adapter (IEmailSender) is required.');\n }\n this.transport = options.transport;\n this.renderer = options.renderer ?? new DefaultEmailRenderer();\n this.defaultFrom = options.defaultFrom;\n this.defaultBrandName = options.defaultBrandName;\n this.brandNameResolver = options.brandNameResolver;\n }\n\n /**\n * Returns the underlying transport instance.\n */\n getTransport(): IEmailSender {\n return this.transport;\n }\n\n /**\n * Renders an email DTO to HTML and plain text without dispatching.\n */\n async render(template: EmailTemplateDto): Promise<RenderedEmail> {\n return await this.renderer.render(template);\n }\n\n /**\n * Legacy positional send signature for backwards compatibility with 0.1.x:\n * `send(to: string, template: EmailTemplateDto, toName?: string): Promise<SendResult>`\n *\n * @deprecated Use `send({ to, template, ... })` instead. This overload will be removed in v1.0.0.\n */\n async send(to: string, template: EmailTemplateDto, toName?: string): Promise<SendResult>;\n /**\n * Sends an email using a strongly-typed template DTO.\n *\n * Example:\n * ```ts\n * await mailer.send({\n * to: 'user@example.com',\n * template: myDto,\n * });\n * ```\n */\n async send(options: SendTemplateOptions): Promise<SendResult>;\n async send(\n toOrOptions: string | SendTemplateOptions,\n maybeTemplate?: EmailTemplateDto,\n maybeToName?: string\n ): Promise<SendResult> {\n const options: SendTemplateOptions =\n typeof toOrOptions === 'string'\n ? {\n to: toOrOptions,\n template: maybeTemplate!,\n toName: maybeToName,\n }\n : toOrOptions;\n\n const template = options.template;\n const recipientName = options.toName ?? template.userName;\n\n // Resolve fromName: explicit option > template.fromName > brand resolver > defaultBrandName\n let resolvedFromName = options.fromName ?? template.fromName;\n if (!resolvedFromName && this.brandNameResolver) {\n resolvedFromName = await this.brandNameResolver();\n }\n if (!resolvedFromName) {\n resolvedFromName = this.defaultBrandName;\n }\n\n // Render template DTO\n const rendered = await this.renderer.render(template);\n const plaintextBody = template.noHtmlMessage ?? rendered.text;\n\n // Format recipients\n let toRecipients: Recipient | Recipient[];\n if (typeof options.to === 'string' && recipientName) {\n toRecipients = { address: options.to, name: recipientName };\n } else {\n toRecipients = options.to;\n }\n\n // Resolve From address\n let from = options.from ?? this.defaultFrom;\n if (resolvedFromName && from) {\n const normalizedFrom = normalizeRecipient(from);\n from = { address: normalizedFrom.address, name: resolvedFromName };\n }\n\n return await this.sendRaw({\n to: toRecipients,\n from,\n subject: template.subject,\n html: rendered.html,\n text: plaintextBody,\n cc: options.cc,\n bcc: options.bcc,\n replyTo: options.replyTo,\n attachments: options.attachments,\n headers: options.headers,\n tags: options.tags,\n metadata: options.metadata,\n });\n }\n\n /**\n * Dispatches a raw, pre-rendered email directly through the transport.\n * If `options.text` is omitted, plain text is automatically derived from `options.html`.\n */\n async sendRaw(options: SendMailOptions): Promise<SendResult> {\n const from = options.from ?? this.defaultFrom;\n const text = options.text ?? (options.html ? htmlToPlainText(options.html) : undefined);\n return await this.transport.send({\n ...options,\n from,\n text,\n });\n }\n\n /**\n * Helper method matching legacy 0.1.x `sendSimpleMessage(to, subject, text, fromName?)`.\n * @deprecated Use `sendRaw({ to, subject, text, ... })` instead. This method will be removed in v1.0.0.\n */\n async sendSimpleMessage(\n to: string,\n subject: string,\n text: string,\n fromName?: string\n ): Promise<SendResult> {\n return await this.sendRaw({\n to,\n subject,\n text,\n html: `<pre style=\"font-family:monospace;white-space:pre-wrap;\">${text}</pre>`,\n from: fromName && this.defaultFrom\n ? { address: normalizeRecipient(this.defaultFrom).address, name: fromName }\n : this.defaultFrom,\n });\n }\n\n /**\n * Legacy helper method to construct plain text from a template.\n * @deprecated Use `render(template)` or `buildPlainText(dto)` instead. This method will be removed in v1.0.0.\n */\n buildPlainTextMessage(template: EmailTemplateDto): string {\n return template.noHtmlMessage ?? buildPlainText(template);\n }\n}\n\n/**\n * Convenience factory to create a MailKit client instance.\n */\nexport function createMailKit(options: MailKitOptions): MailKit {\n return new MailKit(options);\n}\n\n/**\n * Backward-compatibility alias for `MailKit`.\n * @deprecated Use `MailKit` instead. This alias will be removed in v1.0.0.\n */\nexport const EmailService = MailKit;\nexport type EmailService = MailKit;\n","import { ConfigurationError, TransportError } from '../../core/errors.js';\nimport {\n normalizeRecipient,\n normalizeRecipients,\n type SendMailOptions,\n type SendResult,\n} from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\nimport type {\n ZeptoMailHttpConfig,\n ZeptoMailConfig,\n ZeptoMailSendPayload,\n ZeptoMailAttachmentPayload,\n} from './types.js';\n\n/**\n * ZeptoMail (Zoho Mail transactional email HTTP API) transport adapter.\n *\n * Designed for zero dependencies and universal edge compatibility (Node.js, Bun, Deno, Cloudflare Workers)\n * by utilizing the standard global `fetch` API.\n */\nexport class ZeptoMailHttpSender implements IEmailSender {\n readonly name = 'zeptomail';\n\n private readonly apiUrl: string;\n private readonly authHeader: string;\n private readonly defaultFrom: { address: string; name?: string };\n private readonly fetchImpl: typeof fetch;\n\n constructor(config: ZeptoMailHttpConfig) {\n if (!config.apiToken || typeof config.apiToken !== 'string') {\n throw new ConfigurationError('ZeptoMailHttpSender: Missing or invalid apiToken.');\n }\n if (!config.from) {\n throw new ConfigurationError('ZeptoMailHttpSender: Missing required default from address.');\n }\n\n const host = (config.apiHost || 'api.zeptomail.com').replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n this.apiUrl = `https://${host}/v1.1/email`;\n\n // Normalize auth token header. In ZeptoMail, if the user already included \"Zoho-enczapikey \", use as is; otherwise format standard header.\n const token = config.apiToken.trim();\n this.authHeader = token.startsWith('Zoho-') ? token : `Zoho-enczapikey ${token}`;\n\n this.defaultFrom = normalizeRecipient(config.from);\n if (!this.defaultFrom.address) {\n throw new ConfigurationError('ZeptoMailHttpSender: Configured from address must not be empty.');\n }\n\n this.fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof this.fetchImpl !== 'function') {\n throw new ConfigurationError(\n 'ZeptoMailHttpSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailHttpConfig if running on Node < 18.'\n );\n }\n }\n\n /**\n * Dispatches an email using Zoho ZeptoMail API v1.1.\n */\n async send(options: SendMailOptions): Promise<SendResult> {\n const toRecipients = normalizeRecipients(options.to);\n if (toRecipients.length === 0) {\n throw new TransportError('ZeptoMailHttpSender: At least one recipient (to) must be specified.', {\n transportName: this.name,\n });\n }\n\n const resolvedFrom = options.from ? normalizeRecipient(options.from) : this.defaultFrom;\n\n const payload: ZeptoMailSendPayload = {\n from: {\n address: resolvedFrom.address,\n name: resolvedFrom.name,\n },\n to: toRecipients.map((r) => ({\n email_address: {\n address: r.address,\n name: r.name || '',\n },\n })),\n subject: options.subject,\n htmlbody: options.html,\n textbody: options.text,\n };\n\n if (options.cc) {\n const ccList = normalizeRecipients(options.cc);\n if (ccList.length > 0) {\n payload.cc = ccList.map((r) => ({\n email_address: { address: r.address, name: r.name || '' },\n }));\n }\n }\n\n if (options.bcc) {\n const bccList = normalizeRecipients(options.bcc);\n if (bccList.length > 0) {\n payload.bcc = bccList.map((r) => ({\n email_address: { address: r.address, name: r.name || '' },\n }));\n }\n }\n\n if (options.replyTo) {\n const replyToList = normalizeRecipients(options.replyTo);\n if (replyToList.length > 0) {\n payload.reply_to = replyToList.map((r) => ({\n address: r.address,\n name: r.name,\n }));\n }\n }\n\n if (options.attachments && options.attachments.length > 0) {\n payload.attachments = options.attachments.map((att): ZeptoMailAttachmentPayload => {\n let contentBase64: string;\n if (typeof att.content === 'string') {\n contentBase64 = att.content;\n } else {\n // Buffer or Uint8Array\n if (typeof Buffer !== 'undefined') {\n contentBase64 = Buffer.from(att.content).toString('base64');\n } else {\n // Browser / Edge fallback for Uint8Array\n let binary = '';\n const bytes = new Uint8Array(att.content);\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n contentBase64 = btoa(binary);\n }\n }\n\n return {\n name: att.filename,\n content: contentBase64,\n mime_type: att.mimeType || att.contentType || 'application/octet-stream',\n cid: att.cid,\n };\n });\n }\n\n let response: Response;\n try {\n response = await this.fetchImpl(this.apiUrl, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n Authorization: this.authHeader,\n },\n body: JSON.stringify(payload),\n });\n } catch (err) {\n throw new TransportError(`ZeptoMailHttpSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {\n transportName: this.name,\n cause: err,\n });\n }\n\n const responseText = await response.text();\n let responseData: any;\n try {\n responseData = responseText ? JSON.parse(responseText) : {};\n } catch {\n responseData = { raw: responseText };\n }\n\n if (!response.ok) {\n const errorMessage =\n responseData?.error?.message ||\n responseData?.message ||\n `HTTP ${response.status}: ${responseText || response.statusText}`;\n\n throw new TransportError(`ZeptoMailHttpSender: Failed to send email - ${errorMessage}`, {\n transportName: this.name,\n statusCode: response.status,\n responseBody: responseText,\n });\n }\n\n // Extract message ID from standard ZeptoMail v1.1 response structure:\n // { data: [ { message_id: \"...\" } ] }\n const messageId = responseData?.data?.[0]?.message_id;\n\n return {\n success: true,\n messageId,\n response: responseData,\n };\n }\n\n /**\n * Backward-compatible helper method matching legacy signature:\n * `sendEmail(to, htmlBody, subject, toName?, plaintextBody?, fromName?)`\n * @deprecated Use `send({ to, subject, html, text, ... })` instead. This method will be removed in v1.0.0.\n */\n async sendEmail(\n to: string,\n htmlBody: string,\n subject: string,\n toName: string = '',\n plaintextBody?: string,\n fromName?: string\n ): Promise<void> {\n await this.send({\n to: { address: to, name: toName },\n from: fromName ? { address: this.defaultFrom.address, name: fromName } : this.defaultFrom,\n subject,\n html: htmlBody,\n text: plaintextBody,\n });\n }\n}\n\n/**\n * Backward-compatibility alias for `ZeptoMailHttpSender`.\n * @deprecated Use `ZeptoMailHttpSender` instead. This alias will be removed in v1.0.0.\n */\nexport const ZeptoMailSender = ZeptoMailHttpSender;\nexport type ZeptoMailSender = ZeptoMailHttpSender;\n","import type { SendMailOptions, SendResult } from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\n\n/**\n * In-memory email sender for automated testing, local development, and CI environments.\n * Captures all dispatched emails and provides inspection methods.\n */\nexport class MemoryEmailSender implements IEmailSender {\n readonly name = 'memory';\n\n private sentMails: SendMailOptions[] = [];\n private nextId = 1;\n\n async send(options: SendMailOptions): Promise<SendResult> {\n this.sentMails.push({ ...options });\n const messageId = `mem-${this.nextId++}-${Date.now()}`;\n return {\n success: true,\n messageId,\n response: { id: messageId },\n };\n }\n\n /**\n * Returns a copy of all emails sent through this transport instance.\n */\n getSentMails(): SendMailOptions[] {\n return [...this.sentMails];\n }\n\n /**\n * Returns the most recent email sent, or undefined if no emails have been sent.\n */\n getLastMail(): SendMailOptions | undefined {\n return this.sentMails.length > 0\n ? { ...this.sentMails[this.sentMails.length - 1] }\n : undefined;\n }\n\n /**\n * Clears all recorded sent emails.\n */\n clear(): void {\n this.sentMails = [];\n }\n\n /**\n * Returns the total count of sent emails.\n */\n count(): number {\n return this.sentMails.length;\n }\n}\n","import { normalizeRecipients, type SendMailOptions, type SendResult } from '../../core/types.js';\nimport type { IEmailSender } from '../sender.interface.js';\n\nexport interface ConsoleEmailSenderOptions {\n /**\n * Log level or custom log printer. Defaults to `console.log`.\n */\n logger?: (message: string) => void;\n /**\n * Whether to include the full HTML body in console output.\n * Defaults to false (prints plain text or a summary).\n */\n includeHtml?: boolean;\n}\n\n/**\n * Console logger transport that prints dispatched emails to stdout/stderr.\n * Ideal for development and debugging.\n */\nexport class ConsoleEmailSender implements IEmailSender {\n readonly name = 'console';\n\n private readonly log: (message: string) => void;\n private readonly includeHtml: boolean;\n private nextId = 1;\n\n constructor(options: ConsoleEmailSenderOptions = {}) {\n this.log = options.logger ?? console.log;\n this.includeHtml = options.includeHtml ?? false;\n }\n\n async send(options: SendMailOptions): Promise<SendResult> {\n const to = normalizeRecipients(options.to).map((r) => r.name ? `${r.name} <${r.address}>` : r.address).join(', ');\n const from = options.from ? JSON.stringify(options.from) : '(default)';\n const messageId = `console-${this.nextId++}-${Date.now()}`;\n\n const separator = '─'.repeat(60);\n const lines = [\n `\\n┌${separator}┐`,\n `│ [ts-mailkit:console] DISPATCHED EMAIL (${messageId})`,\n `├${separator}┤`,\n `│ From: ${from}`,\n `│ To: ${to}`,\n `│ Subject: ${options.subject}`,\n `├${separator}┤`,\n ];\n\n if (options.text) {\n lines.push('│ Text Body:');\n for (const line of options.text.split('\\n')) {\n lines.push(`│ ${line}`);\n }\n }\n\n if (this.includeHtml && options.html) {\n lines.push('│ HTML Body:');\n for (const line of options.html.split('\\n')) {\n lines.push(`│ ${line}`);\n }\n }\n\n lines.push(`└${separator}┘\\n`);\n\n this.log(lines.join('\\n'));\n\n return {\n success: true,\n messageId,\n response: { logged: true },\n };\n }\n}\n","import type { EmailTemplateDto } from './dto/index.js';\nimport { htmlToPlainText } from '../renderers/utils/html-to-plaintext.js';\n\nexport interface BrandingConfig {\n /**\n * Default brand, application, or company name.\n * @default 'Application'\n */\n brandName?: string;\n\n /**\n * Optional custom security / disclaimer advisory message.\n */\n securityMessage?: string;\n\n /**\n * Optional custom footer generator or string.\n */\n footer?: string | ((brandName: string) => string);\n\n /**\n * Optional default logo URL to display top-center in templated emails.\n */\n logoUrl?: string;\n}\n\nconst DEFAULT_SECURITY_MESSAGE =\n 'If you did not request this, please ignore this email or contact support if you have concerns.';\n\nfunction defaultFooter(brandName: string): string {\n return `&copy; ${new Date().getFullYear()} ${brandName}. All rights reserved.`;\n}\n\n/**\n * Factory for creating pre-populated, type-safe email template DTOs.\n */\nexport class EmailTemplateFactory {\n private readonly defaultBrandName: string;\n private readonly defaultSecurityMessage: string;\n private readonly footerResolver: (brandName: string) => string;\n private readonly defaultLogoUrl?: string;\n\n constructor(config: BrandingConfig = {}) {\n this.defaultBrandName = config.brandName || 'Application';\n this.defaultSecurityMessage = config.securityMessage || DEFAULT_SECURITY_MESSAGE;\n this.defaultLogoUrl = config.logoUrl;\n if (typeof config.footer === 'function') {\n this.footerResolver = config.footer;\n } else if (typeof config.footer === 'string') {\n const fixedFooter = config.footer;\n this.footerResolver = () => fixedFooter;\n } else {\n this.footerResolver = defaultFooter;\n }\n }\n\n private resolveBrand(override?: string): string {\n return override || this.defaultBrandName;\n }\n\n private buildFooter(brandName: string): string {\n return this.footerResolver(brandName);\n }\n\n /**\n * Welcome / email-verification email sent after registration.\n */\n createEmailVerification(\n username: string,\n verificationUrl: string,\n otp: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Thank you for signing up. Use the code below or click the button to verify your email address.`;\n return {\n subject: 'Verify Your Email Address',\n header: `Welcome to ${brand}!`,\n body,\n logoUrl: this.defaultLogoUrl,\n otpCode: otp,\n actionUrl: verificationUrl,\n actionText: 'Verify Email',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage:\n htmlToPlainText(body) +\n `\\n\\nYour verification code is: ${otp}\\n\\nAlternatively, verify here:\\n${verificationUrl}`,\n };\n }\n\n /**\n * Password-reset email with an optional OTP code and action link.\n */\n createPasswordReset(\n username: string,\n resetUrl: string,\n otp: string = '',\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>We received a request to reset your password. Use the OTP code below or click the button to proceed.`;\n const plainTextOtp = otp ? `\\n\\nYour OTP code is: ${otp}` : '';\n return {\n subject: 'Password Reset Request',\n header: 'Reset Your Password',\n body,\n logoUrl: this.defaultLogoUrl,\n otpCode: otp || undefined,\n actionUrl: resetUrl,\n actionText: 'Reset Password',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage:\n htmlToPlainText(body) +\n plainTextOtp +\n `\\n\\nAlternatively, you can use the following link to reset your password:\\n${resetUrl}`,\n };\n }\n\n /**\n * Generic plain message email (no action button, no OTP).\n */\n createSimpleMessage(\n subject: string,\n header: string,\n body: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n return {\n subject,\n header,\n body,\n logoUrl: this.defaultLogoUrl,\n footer: this.buildFooter(brand),\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body),\n };\n }\n\n /**\n * Newsletter / announcement email with an optional hero image and CTA button.\n */\n createNewsLetter(\n subject: string,\n header: string,\n body: string,\n imageUrl?: string,\n actionUrl?: string,\n actionText?: string,\n brandName?: string,\n logoUrl?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n let noHtmlMessage = htmlToPlainText(body);\n if (actionUrl) {\n noHtmlMessage += `\\n\\n${actionText || 'Learn more'}: ${actionUrl}`;\n }\n return {\n subject,\n header,\n body,\n logoUrl: logoUrl || this.defaultLogoUrl,\n imageUrl,\n actionUrl,\n actionText,\n footer: this.buildFooter(brand),\n fromName: brand,\n noHtmlMessage,\n };\n }\n\n /**\n * Two-factor authentication email with OTP code and optional magic link.\n */\n create2FAEmail(\n username: string,\n otp: string,\n magicLink: string = '',\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Use the code below or click the button to complete your login.`;\n const plainLink = magicLink ? `\\n\\nAlternatively, verify here:\\n${magicLink}` : '';\n return {\n subject: 'Your Login Verification Code',\n header: 'Two-Factor Authentication',\n body,\n logoUrl: this.defaultLogoUrl,\n otpCode: otp,\n actionUrl: magicLink || undefined,\n actionText: magicLink ? 'Verify Login' : undefined,\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body) + `\\n\\nYour verification code is: ${otp}` + plainLink,\n };\n }\n\n /**\n * Magic link sign-in email (no OTP, button only).\n */\n createMagicLinkEmail(\n username: string,\n magicLink: string,\n brandName?: string\n ): EmailTemplateDto {\n const brand = this.resolveBrand(brandName);\n const body = `Hi ${username},<br/>Click the button below to sign in. No password needed.`;\n return {\n subject: 'Your Magic Link',\n header: `Sign In to ${brand}`,\n body,\n logoUrl: this.defaultLogoUrl,\n actionUrl: magicLink,\n actionText: 'Sign In',\n extraMessage: this.defaultSecurityMessage,\n footer: this.buildFooter(brand),\n userName: username,\n fromName: brand,\n noHtmlMessage: htmlToPlainText(body) + `\\n\\nSign in here:\\n${magicLink}`,\n };\n }\n\n // ─── Default Static Instance ──────────────────────────────────────────────\n private static _defaultInstance?: EmailTemplateFactory;\n\n private static get defaultInstance(): EmailTemplateFactory {\n if (!this._defaultInstance) {\n this._defaultInstance = new EmailTemplateFactory();\n }\n return this._defaultInstance;\n }\n\n static createEmailVerification(\n username: string,\n verificationUrl: string,\n otp: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createEmailVerification(username, verificationUrl, otp, brandName);\n }\n\n static createPasswordReset(\n username: string,\n resetUrl: string,\n otp?: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createPasswordReset(username, resetUrl, otp, brandName);\n }\n\n static createSimpleMessage(\n subject: string,\n header: string,\n body: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createSimpleMessage(subject, header, body, brandName);\n }\n\n static createNewsLetter(\n subject: string,\n header: string,\n body: string,\n imageUrl?: string,\n actionUrl?: string,\n actionText?: string,\n brandName?: string,\n logoUrl?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createNewsLetter(\n subject,\n header,\n body,\n imageUrl,\n actionUrl,\n actionText,\n brandName,\n logoUrl\n );\n }\n\n static create2FAEmail(\n username: string,\n otp: string,\n magicLink?: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.create2FAEmail(username, otp, magicLink, brandName);\n }\n\n static createMagicLinkEmail(\n username: string,\n magicLink: string,\n brandName?: string\n ): EmailTemplateDto {\n return this.defaultInstance.createMagicLinkEmail(username, magicLink, brandName);\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -1,4 +1,18 @@
1
1
  // src/core/types.ts
2
+ function parseEmailAddress(input) {
3
+ if (!input || typeof input !== "string") {
4
+ return { address: "" };
5
+ }
6
+ const trimmed = input.trim();
7
+ const match = trimmed.match(/^(?:["']?([^"']+)["']?\s+)?<?([^\s<>@]+@[^\s<>@]+)>?$/);
8
+ if (!match) {
9
+ return { address: trimmed };
10
+ }
11
+ return {
12
+ address: match[2].trim(),
13
+ name: match[1]?.trim() || void 0
14
+ };
15
+ }
2
16
  function normalizeRecipient(recipient) {
3
17
  if (typeof recipient === "string") {
4
18
  return { address: recipient.trim() };
@@ -70,6 +84,15 @@ function htmlToPlainText(html) {
70
84
  }
71
85
 
72
86
  // src/renderers/default/default-renderer.ts
87
+ function isValidHttpUrl(urlString) {
88
+ if (!urlString || typeof urlString !== "string") return false;
89
+ try {
90
+ const url = new URL(urlString.trim());
91
+ return (url.protocol === "http:" || url.protocol === "https:") && url.hostname.length > 0;
92
+ } catch {
93
+ return false;
94
+ }
95
+ }
73
96
  function buildPlainText(dto) {
74
97
  if (dto.noHtmlMessage) {
75
98
  return dto.noHtmlMessage;
@@ -112,6 +135,15 @@ function buildHtml(dto, options = {}) {
112
135
  `<body style="margin:0;padding:24px 16px;background-color:#f9fafb;font-family:${fontFamily};color:#1f2937;line-height:1.6;">`,
113
136
  `<div style="max-width:${maxWidth};margin:0 auto;background-color:#ffffff;padding:32px 28px;border-radius:8px;box-shadow:0 1px 3px rgba(0,0,0,0.1);border:1px solid #f3f4f6;">`
114
137
  ];
138
+ const logoCandidate = dto.logoUrl ?? options.logoUrl;
139
+ if (logoCandidate && isValidHttpUrl(logoCandidate)) {
140
+ const validLogo = logoCandidate.trim();
141
+ parts.push(
142
+ `<div style="margin-bottom:24px;text-align:center;">`,
143
+ ` <img src="${validLogo}" alt="${dto.fromName || "Logo"}" style="max-height:48px;max-width:200px;height:auto;width:auto;display:inline-block;border:0;outline:none;text-decoration:none;" />`,
144
+ `</div>`
145
+ );
146
+ }
115
147
  if (dto.imageUrl) {
116
148
  parts.push(
117
149
  `<div style="margin-bottom:24px;text-align:center;">`,
@@ -196,29 +228,15 @@ var MailKit = class {
196
228
  async render(template) {
197
229
  return await this.renderer.render(template);
198
230
  }
199
- /**
200
- * Returns the plain-text fallback for an email DTO without sending.
201
- */
202
- buildPlainTextMessage(template) {
203
- return template.noHtmlMessage ?? buildPlainText(template);
204
- }
205
- async send(optionsOrTo, maybeTemplate, maybeToName) {
206
- let opts;
207
- if (typeof optionsOrTo === "string") {
208
- if (!maybeTemplate) {
209
- throw new ConfigurationError("MailKit.send: Missing required template DTO argument.");
210
- }
211
- opts = {
212
- to: optionsOrTo,
213
- template: maybeTemplate,
214
- toName: maybeToName
215
- };
216
- } else {
217
- opts = optionsOrTo;
218
- }
219
- const template = opts.template;
220
- const recipientName = opts.toName ?? template.userName;
221
- let resolvedFromName = opts.fromName ?? template.fromName;
231
+ async send(toOrOptions, maybeTemplate, maybeToName) {
232
+ const options = typeof toOrOptions === "string" ? {
233
+ to: toOrOptions,
234
+ template: maybeTemplate,
235
+ toName: maybeToName
236
+ } : toOrOptions;
237
+ const template = options.template;
238
+ const recipientName = options.toName ?? template.userName;
239
+ let resolvedFromName = options.fromName ?? template.fromName;
222
240
  if (!resolvedFromName && this.brandNameResolver) {
223
241
  resolvedFromName = await this.brandNameResolver();
224
242
  }
@@ -228,12 +246,12 @@ var MailKit = class {
228
246
  const rendered = await this.renderer.render(template);
229
247
  const plaintextBody = template.noHtmlMessage ?? rendered.text;
230
248
  let toRecipients;
231
- if (typeof opts.to === "string" && recipientName) {
232
- toRecipients = { address: opts.to, name: recipientName };
249
+ if (typeof options.to === "string" && recipientName) {
250
+ toRecipients = { address: options.to, name: recipientName };
233
251
  } else {
234
- toRecipients = opts.to;
252
+ toRecipients = options.to;
235
253
  }
236
- let from = opts.from ?? this.defaultFrom;
254
+ let from = options.from ?? this.defaultFrom;
237
255
  if (resolvedFromName && from) {
238
256
  const normalizedFrom = normalizeRecipient(from);
239
257
  from = { address: normalizedFrom.address, name: resolvedFromName };
@@ -244,46 +262,56 @@ var MailKit = class {
244
262
  subject: template.subject,
245
263
  html: rendered.html,
246
264
  text: plaintextBody,
247
- cc: opts.cc,
248
- bcc: opts.bcc,
249
- replyTo: opts.replyTo,
250
- attachments: opts.attachments,
251
- headers: opts.headers,
252
- tags: opts.tags,
253
- metadata: opts.metadata
265
+ cc: options.cc,
266
+ bcc: options.bcc,
267
+ replyTo: options.replyTo,
268
+ attachments: options.attachments,
269
+ headers: options.headers,
270
+ tags: options.tags,
271
+ metadata: options.metadata
254
272
  });
255
273
  }
256
274
  /**
257
275
  * Dispatches a raw, pre-rendered email directly through the transport.
276
+ * If `options.text` is omitted, plain text is automatically derived from `options.html`.
258
277
  */
259
278
  async sendRaw(options) {
260
279
  const from = options.from ?? this.defaultFrom;
280
+ const text = options.text ?? (options.html ? htmlToPlainText(options.html) : void 0);
261
281
  return await this.transport.send({
262
282
  ...options,
263
- from
283
+ from,
284
+ text
264
285
  });
265
286
  }
266
287
  /**
267
- * Sends a raw plain-text email with basic HTML pre-formatting.
268
- * Useful for plain notifications, alerts, or simple text messages.
288
+ * Helper method matching legacy 0.1.x `sendSimpleMessage(to, subject, text, fromName?)`.
289
+ * @deprecated Use `sendRaw({ to, subject, text, ... })` instead. This method will be removed in v1.0.0.
269
290
  */
270
- async sendSimpleMessage(to, subject, text, toName = "") {
271
- const html = `<pre style="font-family:monospace;white-space:pre-wrap;">${text}</pre>`;
291
+ async sendSimpleMessage(to, subject, text, fromName) {
272
292
  return await this.sendRaw({
273
- to: { address: to, name: toName },
293
+ to,
274
294
  subject,
275
- html,
276
- text
295
+ text,
296
+ html: `<pre style="font-family:monospace;white-space:pre-wrap;">${text}</pre>`,
297
+ from: fromName && this.defaultFrom ? { address: normalizeRecipient(this.defaultFrom).address, name: fromName } : this.defaultFrom
277
298
  });
278
299
  }
300
+ /**
301
+ * Legacy helper method to construct plain text from a template.
302
+ * @deprecated Use `render(template)` or `buildPlainText(dto)` instead. This method will be removed in v1.0.0.
303
+ */
304
+ buildPlainTextMessage(template) {
305
+ return template.noHtmlMessage ?? buildPlainText(template);
306
+ }
279
307
  };
280
- var EmailService = MailKit;
281
308
  function createMailKit(options) {
282
309
  return new MailKit(options);
283
310
  }
311
+ var EmailService = MailKit;
284
312
 
285
313
  // src/transports/zeptomail/zeptomail-sender.ts
286
- var ZeptoMailSender = class {
314
+ var ZeptoMailHttpSender = class {
287
315
  name = "zeptomail";
288
316
  apiUrl;
289
317
  authHeader;
@@ -291,10 +319,10 @@ var ZeptoMailSender = class {
291
319
  fetchImpl;
292
320
  constructor(config) {
293
321
  if (!config.apiToken || typeof config.apiToken !== "string") {
294
- throw new ConfigurationError("ZeptoMailSender: Missing or invalid apiToken.");
322
+ throw new ConfigurationError("ZeptoMailHttpSender: Missing or invalid apiToken.");
295
323
  }
296
324
  if (!config.from) {
297
- throw new ConfigurationError("ZeptoMailSender: Missing required default from address.");
325
+ throw new ConfigurationError("ZeptoMailHttpSender: Missing required default from address.");
298
326
  }
299
327
  const host = (config.apiHost || "api.zeptomail.com").replace(/^https?:\/\//, "").replace(/\/+$/, "");
300
328
  this.apiUrl = `https://${host}/v1.1/email`;
@@ -302,12 +330,12 @@ var ZeptoMailSender = class {
302
330
  this.authHeader = token.startsWith("Zoho-") ? token : `Zoho-enczapikey ${token}`;
303
331
  this.defaultFrom = normalizeRecipient(config.from);
304
332
  if (!this.defaultFrom.address) {
305
- throw new ConfigurationError("ZeptoMailSender: Configured from address must not be empty.");
333
+ throw new ConfigurationError("ZeptoMailHttpSender: Configured from address must not be empty.");
306
334
  }
307
335
  this.fetchImpl = config.fetch ?? globalThis.fetch;
308
336
  if (typeof this.fetchImpl !== "function") {
309
337
  throw new ConfigurationError(
310
- "ZeptoMailSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailConfig if running on Node < 18."
338
+ "ZeptoMailHttpSender: No global fetch implementation found. Pass a custom fetch to ZeptoMailHttpConfig if running on Node < 18."
311
339
  );
312
340
  }
313
341
  }
@@ -317,7 +345,7 @@ var ZeptoMailSender = class {
317
345
  async send(options) {
318
346
  const toRecipients = normalizeRecipients(options.to);
319
347
  if (toRecipients.length === 0) {
320
- throw new TransportError("ZeptoMailSender: At least one recipient (to) must be specified.", {
348
+ throw new TransportError("ZeptoMailHttpSender: At least one recipient (to) must be specified.", {
321
349
  transportName: this.name
322
350
  });
323
351
  }
@@ -399,7 +427,7 @@ var ZeptoMailSender = class {
399
427
  body: JSON.stringify(payload)
400
428
  });
401
429
  } catch (err) {
402
- throw new TransportError(`ZeptoMailSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {
430
+ throw new TransportError(`ZeptoMailHttpSender: Network request failed: ${err instanceof Error ? err.message : String(err)}`, {
403
431
  transportName: this.name,
404
432
  cause: err
405
433
  });
@@ -413,7 +441,7 @@ var ZeptoMailSender = class {
413
441
  }
414
442
  if (!response.ok) {
415
443
  const errorMessage = responseData?.error?.message || responseData?.message || `HTTP ${response.status}: ${responseText || response.statusText}`;
416
- throw new TransportError(`ZeptoMailSender: Failed to send email - ${errorMessage}`, {
444
+ throw new TransportError(`ZeptoMailHttpSender: Failed to send email - ${errorMessage}`, {
417
445
  transportName: this.name,
418
446
  statusCode: response.status,
419
447
  responseBody: responseText
@@ -429,6 +457,7 @@ var ZeptoMailSender = class {
429
457
  /**
430
458
  * Backward-compatible helper method matching legacy signature:
431
459
  * `sendEmail(to, htmlBody, subject, toName?, plaintextBody?, fromName?)`
460
+ * @deprecated Use `send({ to, subject, html, text, ... })` instead. This method will be removed in v1.0.0.
432
461
  */
433
462
  async sendEmail(to, htmlBody, subject, toName = "", plaintextBody, fromName) {
434
463
  await this.send({
@@ -440,6 +469,7 @@ var ZeptoMailSender = class {
440
469
  });
441
470
  }
442
471
  };
472
+ var ZeptoMailSender = ZeptoMailHttpSender;
443
473
 
444
474
  // src/transports/memory/memory-sender.ts
445
475
  var MemoryEmailSender = class {
@@ -538,9 +568,11 @@ var EmailTemplateFactory = class _EmailTemplateFactory {
538
568
  defaultBrandName;
539
569
  defaultSecurityMessage;
540
570
  footerResolver;
571
+ defaultLogoUrl;
541
572
  constructor(config = {}) {
542
573
  this.defaultBrandName = config.brandName || "Application";
543
574
  this.defaultSecurityMessage = config.securityMessage || DEFAULT_SECURITY_MESSAGE;
575
+ this.defaultLogoUrl = config.logoUrl;
544
576
  if (typeof config.footer === "function") {
545
577
  this.footerResolver = config.footer;
546
578
  } else if (typeof config.footer === "string") {
@@ -566,6 +598,7 @@ var EmailTemplateFactory = class _EmailTemplateFactory {
566
598
  subject: "Verify Your Email Address",
567
599
  header: `Welcome to ${brand}!`,
568
600
  body,
601
+ logoUrl: this.defaultLogoUrl,
569
602
  otpCode: otp,
570
603
  actionUrl: verificationUrl,
571
604
  actionText: "Verify Email",
@@ -594,6 +627,7 @@ Your OTP code is: ${otp}` : "";
594
627
  subject: "Password Reset Request",
595
628
  header: "Reset Your Password",
596
629
  body,
630
+ logoUrl: this.defaultLogoUrl,
597
631
  otpCode: otp || void 0,
598
632
  actionUrl: resetUrl,
599
633
  actionText: "Reset Password",
@@ -616,6 +650,7 @@ ${resetUrl}`
616
650
  subject,
617
651
  header,
618
652
  body,
653
+ logoUrl: this.defaultLogoUrl,
619
654
  footer: this.buildFooter(brand),
620
655
  fromName: brand,
621
656
  noHtmlMessage: htmlToPlainText(body)
@@ -624,7 +659,7 @@ ${resetUrl}`
624
659
  /**
625
660
  * Newsletter / announcement email with an optional hero image and CTA button.
626
661
  */
627
- createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName) {
662
+ createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl) {
628
663
  const brand = this.resolveBrand(brandName);
629
664
  let noHtmlMessage = htmlToPlainText(body);
630
665
  if (actionUrl) {
@@ -636,6 +671,7 @@ ${actionText || "Learn more"}: ${actionUrl}`;
636
671
  subject,
637
672
  header,
638
673
  body,
674
+ logoUrl: logoUrl || this.defaultLogoUrl,
639
675
  imageUrl,
640
676
  actionUrl,
641
677
  actionText,
@@ -658,6 +694,7 @@ ${magicLink}` : "";
658
694
  subject: "Your Login Verification Code",
659
695
  header: "Two-Factor Authentication",
660
696
  body,
697
+ logoUrl: this.defaultLogoUrl,
661
698
  otpCode: otp,
662
699
  actionUrl: magicLink || void 0,
663
700
  actionText: magicLink ? "Verify Login" : void 0,
@@ -680,6 +717,7 @@ Your verification code is: ${otp}` + plainLink
680
717
  subject: "Your Magic Link",
681
718
  header: `Sign In to ${brand}`,
682
719
  body,
720
+ logoUrl: this.defaultLogoUrl,
683
721
  actionUrl: magicLink,
684
722
  actionText: "Sign In",
685
723
  extraMessage: this.defaultSecurityMessage,
@@ -709,7 +747,7 @@ ${magicLink}`
709
747
  static createSimpleMessage(subject, header, body, brandName) {
710
748
  return this.defaultInstance.createSimpleMessage(subject, header, body, brandName);
711
749
  }
712
- static createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName) {
750
+ static createNewsLetter(subject, header, body, imageUrl, actionUrl, actionText, brandName, logoUrl) {
713
751
  return this.defaultInstance.createNewsLetter(
714
752
  subject,
715
753
  header,
@@ -717,7 +755,8 @@ ${magicLink}`
717
755
  imageUrl,
718
756
  actionUrl,
719
757
  actionText,
720
- brandName
758
+ brandName,
759
+ logoUrl
721
760
  );
722
761
  }
723
762
  static create2FAEmail(username, otp, magicLink, brandName) {
@@ -738,13 +777,16 @@ export {
738
777
  MemoryEmailSender,
739
778
  TemplateError,
740
779
  TransportError,
780
+ ZeptoMailHttpSender,
741
781
  ZeptoMailSender,
742
782
  buildHtml,
743
783
  buildPlainText,
744
784
  createMailKit,
745
785
  decodeHtmlEntities,
746
786
  htmlToPlainText,
787
+ isValidHttpUrl,
747
788
  normalizeRecipient,
748
- normalizeRecipients
789
+ normalizeRecipients,
790
+ parseEmailAddress
749
791
  };
750
792
  //# sourceMappingURL=index.js.map