import nodemailer, { type SendMailOptions } from "nodemailer"; import { getMailSettings } from "@/lib/app-config"; import type { AppLocale } from "@/lib/locale"; import type { MailSettings } from "@/lib/mail-settings"; type MailTransportOptions = { host: string; port: number; secure: boolean; auth: { user: string; pass: string; }; }; type MailTransport = { sendMail: (options: SendMailOptions) => Promise; }; type CreateTransport = (options: MailTransportOptions) => MailTransport; type SendMailDeps = { settings?: MailSettings; createTransport?: CreateTransport; }; type SendMailInput = { to: string; subject: string; text: string; replyTo?: string; }; type ContactMessageInput = { name: string; email: string; phone?: string; company?: string; message: string; locale: AppLocale; }; function requireValue(value: string, message: string) { if (!value.trim()) { throw new Error(message); } return value.trim(); } function getConfiguredTransportSettings(settings: MailSettings) { const smtpHost = requireValue(settings.smtp.host, "SMTP host is required."); const smtpUsername = requireValue(settings.smtp.username, "SMTP username is required."); const smtpPassword = requireValue(settings.smtp.password, "SMTP password is required."); const fromEmail = requireValue(settings.sender.email, "From email is required."); return { smtpHost, smtpUsername, smtpPassword, fromEmail, }; } function getConfiguredRecipient(settings: MailSettings, recipientKey: "contact" | "test") { if (recipientKey === "contact") { return requireValue( settings.recipients.contact || settings.recipients.test, "Contact recipient email is required.", ); } return requireValue( settings.recipients.test || settings.recipients.contact, "Test recipient email is required.", ); } export function createSmtpTransport( settings: MailSettings, createTransport: CreateTransport = nodemailer.createTransport, ) { const { smtpHost, smtpUsername, smtpPassword } = getConfiguredTransportSettings(settings); return createTransport({ host: smtpHost, port: settings.smtp.port, secure: settings.smtp.secure, auth: { user: smtpUsername, pass: smtpPassword, }, }); } export async function sendMail( input: SendMailInput, deps: SendMailDeps = {}, ) { const settings = deps.settings ?? await getMailSettings(); const { fromEmail } = getConfiguredTransportSettings(settings); const transport = createSmtpTransport(settings, deps.createTransport); await transport.sendMail({ from: settings.sender.name ? `${settings.sender.name} <${fromEmail}>` : fromEmail, to: input.to, subject: input.subject, text: input.text, replyTo: input.replyTo, }); } export async function sendContactMessage( input: ContactMessageInput, deps: SendMailDeps = {}, ) { const settings = deps.settings ?? await getMailSettings(); const recipient = getConfiguredRecipient(settings, "contact"); await sendMail( { to: recipient, subject: "New contact message", replyTo: input.email, text: [ "A new contact message was submitted.", "", `Name: ${input.name}`, `Email: ${input.email}`, `Phone: ${input.phone?.trim() || "-"}`, `Company: ${input.company?.trim() || "-"}`, `Locale: ${input.locale}`, `Submitted at: ${new Date().toISOString()}`, "", "Message:", input.message, ].join("\n"), }, { settings, createTransport: deps.createTransport, }, ); } export async function sendTestEmail( deps: SendMailDeps = {}, ) { const settings = deps.settings ?? await getMailSettings(); const recipient = getConfiguredRecipient(settings, "test"); const { fromEmail } = getConfiguredTransportSettings(settings); await sendMail( { to: recipient, subject: "SMTP test email", text: [ "This is a backend SMTP test email.", "", `Timestamp: ${new Date().toISOString()}`, `Configured from email: ${fromEmail}`, `Configured recipient: ${recipient}`, `Environment: ${process.env.NODE_ENV ?? "development"}`, ].join("\n"), }, { settings, createTransport: deps.createTransport, }, ); }