import nodemailer from 'nodemailer'; import { getServerAppServices } from '@/lib/services/create-services.server'; import { config } from '../config'; let transporterInstance: nodemailer.Transporter | null = null; function getTransporter() { if (transporterInstance) return transporterInstance; if (!config.mail.host) { throw new Error('MAIL_HOST is not configured. Please check your environment variables.'); } transporterInstance = nodemailer.createTransport({ host: config.mail.host, port: config.mail.port, secure: config.mail.port === 465, auth: { user: config.mail.user, pass: config.mail.pass, }, }); return transporterInstance; } interface SendEmailOptions { to?: string | string[]; replyTo?: string; subject: string; html: string; } export async function sendEmail({ to, replyTo, subject, html }: SendEmailOptions) { const logger = getServerAppServices().logger.child({ component: 'mailer' }); // Resolve recipients: priority to 'to' override, fallback to global MAIL_RECIPIENTS const resolvedTo = to || config.mail.recipients; // Normalize recipients (handle arrays or comma-strings) const recipients = Array.isArray(resolvedTo) ? resolvedTo.join(', ') : (resolvedTo?.toString() || ''); if (!recipients || recipients.trim() === '') { logger.error('Email delivery ABORTED: No recipients configured', { subject, providedTo: to, configRecipients: config.mail.recipients }); return { success: false as const, error: 'No recipients configured' }; } if (!config.mail.from) { logger.error('Email delivery ABORTED: MAIL_FROM is missing', { subject, recipients }); return { success: false as const, error: 'MAIL_FROM is not configured' }; } const mailOptions = { from: config.mail.from, to: recipients, replyTo, subject, html, }; try { const transporter = getTransporter(); logger.info('Attempting to send email via SMTP', { host: config.mail.host, subject, recipients, hasReplyTo: !!replyTo }); const info = await transporter.sendMail(mailOptions); logger.info('Email sent successfully', { messageId: info.messageId, subject, recipients, response: info.response }); return { success: true, messageId: info.messageId }; } catch (error) { const errorMsg = error instanceof Error ? error.message : String(error); logger.error('SMTP Transport failed', { error: errorMsg, subject, recipients, config: { host: config.mail.host, user: config.mail.user ? '***' : 'not set' } }); return { success: false, error: errorMsg }; } }