const nodemailer = require("nodemailer"); const { NotificationTemplate } = require("../models"); // adjust path if needed const logger = require("../services/logger"); require("dotenv").config(); const { sanitizeForLog } = require("../utils/sanitize"); const port = Number(process.env.MAIL_PORT); const transporter = nodemailer.createTransport({ host: process.env.MAIL_HOST, port, secure: port === 465, // SSL requireTLS: port === 587, // Enforce TLS for 587 auth: { user: process.env.MAIL_USER, pass: process.env.MAIL_PASS, }, }); /** * Replace placeholders in template HTML with actual data */ // function replacePlaceholders(templateHtml, data) { // let html = templateHtml; // for (const key in data) { // const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g"); // html = html.replace(regex, data[key]); // } // return html; // } function replacePlaceholders(templateHtml, data) { if(!templateHtml) return ""; let html = templateHtml; for (const key in data) { const safeValue = data[key] ?? ""; const regex = new RegExp(`{{\\s*${key}\\s*}}`, "g"); html = html.replace(regex, safeValue); } return html; } exports.sendEmailService = async (to, templateCode, data = {}) => { const sanitizedTo = sanitizeForLog(to); const sanitizedTemplate = sanitizeForLog(templateCode); const sanitizedData = sanitizeForLog( typeof data === "object" ? JSON.stringify(data) : String(data) ); const logPrefix = `[EMAIL SERVICE][${new Date().toISOString()}]`; logger.info(`${logPrefix} → Starting email process`); logger.info(`${logPrefix} → Template Code: ${sanitizedTemplate}`); logger.info(`${logPrefix} → Recipient: ${sanitizedTo}`); logger.info(`${logPrefix} → Placeholder Data: ${sanitizedData}`); try { // 1. Fetch template from DB const template = await NotificationTemplate.findOne({ where: { template_code: templateCode }, }); if (!template) { logger.error(`${logPrefix} ❌ Template not found for code:${sanitizedTemplate}`); throw new Error(`Template not found for code: ${templateCode}`); } // 2. Replace placeholders const html = replacePlaceholders(template.body_html, data); // 3. Prepare mail options const mailOptions = { from: process.env.SMTP_FROM || process.env.SMTP_USER, to, subject: template.subject || "Notification", html, }; logger.info(`${logPrefix} ✉️ Sending email using SMTP...`); // 4. Send mail const info = await transporter.sendMail(mailOptions); logger.info(`${logPrefix} ✅ Email sent successfully`); logger.info(`${logPrefix} Message ID: ${sanitizeForLog(info.messageId)}`); logger.info(`${logPrefix} Response: ${info.response}`); return { status: "ok", message: "Email sent successfully", messageId: info.messageId, response: info.response, to, subject: template.subject, templateCode, }; } catch (err) { logger.error(`${logPrefix} ❌ Email sending failed`); logger.error(`${logPrefix} Error: ${err.message}`); if (err.stack) logger.error(`${logPrefix} Stack: ${err.stack}`); return { status: "failed", message: err.message, templateCode, to, error: err.stack || err.message, }; } };