import { createTransport, type Transporter } from 'nodemailer'; import { env } from '../../config/env.js'; let transporter: Transporter | null = null; function getTransporter(): Transporter { if (!transporter) { if (!env.SMTP_USER || !env.SMTP_PASS) { console.warn('[EMAIL] SMTP not configured. Emails will be logged to console.'); return { sendMail: async (opts: any) => { console.log('[EMAIL] Would send:', { to: opts.to, subject: opts.subject }); return { messageId: 'mock' }; }, } as any; } transporter = createTransport({ host: env.SMTP_HOST, port: parseInt(env.SMTP_PORT), secure: false, // Upgrade to TLS via STARTTLS requireTLS: true, // Reject if STARTTLS is not available auth: { user: env.SMTP_USER, pass: env.SMTP_PASS, }, }); } return transporter; } async function sendEmail(to: string, subject: string, html: string) { const transport = getTransporter(); try { await transport.sendMail({ from: env.SMTP_FROM, to, subject, html, text: html.replace(/<[^>]*>/g, ''), }); } catch (error) { console.error('[EMAIL] Error sending email:', error); // Don't throw — email failure shouldn't break the main flow } } export const emailService = { sendWelcome: async (to: string, data: { nombre: string; email: string; tempPassword: string }) => { const { welcomeEmail } = await import('./templates/welcome.js'); await sendEmail(to, 'Bienvenido a Horux360', welcomeEmail(data)); }, sendFielNotification: async (data: { clienteNombre: string; clienteRfc: string }) => { const { fielNotificationEmail } = await import('./templates/fiel-notification.js'); await sendEmail(env.ADMIN_EMAIL, `[${data.clienteNombre}] subió su FIEL`, fielNotificationEmail(data)); }, sendPaymentConfirmed: async (to: string, data: { nombre: string; amount: number; plan: string; date: string }) => { const { paymentConfirmedEmail } = await import('./templates/payment-confirmed.js'); await sendEmail(to, 'Confirmación de pago - Horux360', paymentConfirmedEmail(data)); }, sendPaymentFailed: async (to: string, data: { nombre: string; amount: number; plan: string }) => { const { paymentFailedEmail } = await import('./templates/payment-failed.js'); await sendEmail(to, 'Problema con tu pago - Horux360', paymentFailedEmail(data)); await sendEmail(env.ADMIN_EMAIL, `Pago fallido: ${data.nombre}`, paymentFailedEmail(data)); }, sendSubscriptionExpiring: async (to: string, data: { nombre: string; plan: string; expiresAt: string }) => { const { subscriptionExpiringEmail } = await import('./templates/subscription-expiring.js'); await sendEmail(to, 'Tu suscripción vence en 5 días', subscriptionExpiringEmail(data)); }, sendSubscriptionCancelled: async (to: string, data: { nombre: string; plan: string }) => { const { subscriptionCancelledEmail } = await import('./templates/subscription-cancelled.js'); await sendEmail(to, 'Suscripción cancelada - Horux360', subscriptionCancelledEmail(data)); await sendEmail(env.ADMIN_EMAIL, `Suscripción cancelada: ${data.nombre}`, subscriptionCancelledEmail(data)); }, sendNewClientAdmin: async (data: { clienteNombre: string; clienteRfc: string; adminEmail: string; adminNombre: string; tempPassword: string; databaseName: string; plan: string; }) => { const { newClientAdminEmail } = await import('./templates/new-client-admin.js'); await sendEmail(env.ADMIN_EMAIL, `Nuevo cliente: ${data.clienteNombre} (${data.clienteRfc})`, newClientAdminEmail(data)); }, };