118 lines
3.4 KiB
JavaScript
118 lines
3.4 KiB
JavaScript
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,
|
|
};
|
|
}
|
|
}; |