111 lines
3.7 KiB
TypeScript
111 lines
3.7 KiB
TypeScript
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<void> {
|
|
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;
|