Files
klz-cables.com/lib/mail/mailer.ts

100 lines
2.7 KiB
TypeScript

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 };
}
}