import nodemailer from "nodemailer"; import Mail from "nodemailer/lib/mailer"; import SMTPTransport from "nodemailer/lib/smtp-transport"; import { INotificationSender } from "../notification.dispatcher.service"; import { ProcessedNotification } from "../notification.processor.service"; import { EmailConfig } from "../../types/notification.types"; import { settingsService } from "../settings.service"; class EmailSenderService implements INotificationSender { async send(notification: ProcessedNotification): Promise { const config = notification.config as EmailConfig; const { to, smtpHost, smtpPort, smtpSecure, smtpUser, smtpPass, from } = config; const subject = notification.subject || "Notification"; const body = notification.body; if (!to) { console.error( "[EmailSender] Missing recipient address (to) in configuration." ); throw new Error( "Email configuration is incomplete (missing recipient address)." ); } try { const globalSmtpHost = await settingsService.getSetting("smtpHost"); const globalSmtpPortStr = await settingsService.getSetting("smtpPort"); const globalSmtpSecureStr = await settingsService.getSetting( "smtpSecure" ); const globalSmtpUser = await settingsService.getSetting("smtpUser"); const globalSmtpPass = await settingsService.getSetting("smtpPass"); const globalSmtpFrom = await settingsService.getSetting("smtpFrom"); const finalSmtpHost = smtpHost || globalSmtpHost; const finalSmtpPort = smtpPort ?? (globalSmtpPortStr ? parseInt(globalSmtpPortStr, 10) : 587); const finalSmtpSecure = smtpSecure ?? globalSmtpSecureStr === "true" ?? false; const finalSmtpUser = smtpUser || globalSmtpUser; const finalSmtpPass = smtpPass || globalSmtpPass; const finalFrom = from || globalSmtpFrom || "noreply@nexus-terminal.local"; if (!finalSmtpHost) { console.error( "[EmailSender] SMTP host is not configured (neither channel-specific nor global)." ); throw new Error("SMTP host configuration is missing."); } if (isNaN(finalSmtpPort) || finalSmtpPort <= 0) { console.error( `[EmailSender] Invalid SMTP port configured: ${finalSmtpPort}. Using default 587.` ); throw new Error(`Invalid SMTP port configured: ${finalSmtpPort}`); } const transporterOptions: SMTPTransport.Options = { host: finalSmtpHost, port: finalSmtpPort, secure: finalSmtpSecure, auth: finalSmtpUser && finalSmtpPass ? { user: finalSmtpUser, pass: finalSmtpPass, } : undefined, tls: { rejectUnauthorized: finalSmtpSecure, minVersion: "TLSv1.2", }, }; const transporter = nodemailer.createTransport(transporterOptions); const mailOptions: Mail.Options = { from: `"${finalFrom.split("@")[0]}" <${finalFrom}>`, to: to, subject: subject, html: body, }; console.log( `[EmailSender] Sending email notification to: ${to} with subject: "${subject}"` ); const info = await transporter.sendMail(mailOptions); console.log( `[EmailSender] Email sent successfully. Message ID: ${info.messageId}` ); } catch (error: any) { console.error( `[EmailSender] Error sending email notification to ${to}:`, error ); throw new Error( `Failed to send email notification: ${error.message || error}` ); } } } const emailSenderService = new EmailSenderService(); export default emailSenderService;