Files
John 69b4e68baf
SAP-ERP Portal CI/CD / build (push) Failing after 5m20s
first commit
2026-09-23 17:31:02 +05:30

75 lines
2.9 KiB
JavaScript

// services/mailer.js
// Thin nodemailer wrapper for stage-change email notifications (Production
// module). SMTP credentials come from .env (SMTP_HOST/PORT/SECURE/USER/
// PASSWORD/FROM) — there is no SMTP config in the Admin UI. Until SMTP_HOST
// is set, sendMail() is a safe no-op (logs and resolves) so the rest of the
// notification pipeline (and the request that triggered it) never breaks
// because email isn't configured yet.
'use strict';
const nodemailer = require('nodemailer');
let _transporter = null;
function isConfigured() {
return !!process.env.SMTP_HOST;
}
function getTransporter() {
if (_transporter) return _transporter;
_transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT) || 587,
secure: String(process.env.SMTP_SECURE).toLowerCase() === 'true',
auth: process.env.SMTP_USER ? { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD } : undefined,
});
return _transporter;
}
const mailLog = () => require('./mailLogStore');
// Never throws — logs and resolves so a mail failure can't break the caller's
// request. Returns true if actually sent, false if skipped/failed. Every
// outcome (sent/failed/skipped) is also recorded to the Mail Log (see
// services/mailLogStore.js, viewer at /mail-logs) so delivery can be
// confirmed without digging through console output.
async function sendMail({ to, subject, html, text }) {
const recipients = Array.isArray(to) ? to.filter(Boolean) : [to].filter(Boolean);
if (!recipients.length) return false;
if (!isConfigured()) {
console.log(`[MAILER] SMTP not configured — skipping email "${subject}" to ${recipients.join(', ')}`);
await mailLog().record({ to: recipients, subject, status: 'SKIPPED', error: 'SMTP not configured' });
return false;
}
try {
const info = await getTransporter().sendMail({
from: process.env.SMTP_FROM || process.env.SMTP_USER,
to: recipients.join(', '),
subject,
html,
text: text || undefined,
});
console.log(`[MAILER] sent "${subject}" to ${recipients.join(', ')} (messageId: ${info.messageId})`);
await mailLog().record({ to: recipients, subject, status: 'SENT', messageId: info.messageId });
return true;
} catch (e) {
console.error(`[MAILER] send FAILED for "${subject}" to ${recipients.join(', ')}:`, e.message);
await mailLog().record({ to: recipients, subject, status: 'FAILED', error: e.message });
return false;
}
}
// Checks the SMTP connection/credentials without sending anything — surfaces
// the real error (bad host, auth rejected, etc.) rather than a generic
// send failure.
async function verifyConnection() {
if (!isConfigured()) return { ok: false, message: 'SMTP_HOST is not set in .env' };
try {
await getTransporter().verify();
return { ok: true };
} catch (e) {
return { ok: false, message: e.message };
}
}
module.exports = { sendMail, isConfigured, verifyConnection };