Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
140 lines
4 KiB
JavaScript
140 lines
4 KiB
JavaScript
import nodemailer from 'nodemailer';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import { logger } from './logger.js';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const SMTP_CONFIG_FILE = path.join(__dirname, '../smtp-config.json');
|
|
|
|
/**
|
|
* Send email with SMTP fallback logic
|
|
*/
|
|
export async function sendEmailWithFallback(to, subject, html) {
|
|
// Load SMTP accounts from config
|
|
let smtpAccounts = [];
|
|
try {
|
|
if (fs.existsSync(SMTP_CONFIG_FILE)) {
|
|
const data = fs.readFileSync(SMTP_CONFIG_FILE, 'utf8');
|
|
const config = JSON.parse(data);
|
|
smtpAccounts = config.accounts || [];
|
|
}
|
|
} catch (error) {
|
|
logger.error({ err: error }, 'Error loading SMTP config');
|
|
return { success: false, error: 'Failed to load SMTP configuration' };
|
|
}
|
|
|
|
if (smtpAccounts.length === 0) {
|
|
logger.error('❌ No SMTP accounts configured');
|
|
return { success: false, error: 'No SMTP accounts configured' };
|
|
}
|
|
|
|
// Try each SMTP account in order (PRIMARY first, then FALLBACKs)
|
|
for (let i = 0; i < smtpAccounts.length; i++) {
|
|
const account = smtpAccounts[i];
|
|
const accountLabel = i === 0 ? 'PRIMARY' : `FALLBACK #${i}`;
|
|
|
|
logger.info(`📧 Attempting to send email via ${accountLabel}: ${account.name} (${account.user})`);
|
|
|
|
try {
|
|
// Create transporter configuration
|
|
const transportConfig = {
|
|
host: account.host,
|
|
port: parseInt(account.port) || 587,
|
|
secure: parseInt(account.port) === 465,
|
|
tls: {
|
|
rejectUnauthorized: false
|
|
}
|
|
};
|
|
|
|
// Only add auth if user/password are provided
|
|
if (account.user && account.password) {
|
|
transportConfig.auth = {
|
|
user: account.user,
|
|
pass: account.password
|
|
};
|
|
}
|
|
|
|
const transporter = nodemailer.createTransport(transportConfig);
|
|
|
|
// Determine FROM address
|
|
let fromAddress;
|
|
if (account.fromEmail) {
|
|
fromAddress = account.fromEmail;
|
|
} else if (account.user) {
|
|
fromAddress = account.user;
|
|
} else if (account.host === '127.0.0.1' || account.host === 'localhost') {
|
|
fromAddress = 'noreply@hltrn.cc';
|
|
} else {
|
|
fromAddress = `noreply@${account.host.replace(/^(smtp\.|mail\.)/, '')}`;
|
|
}
|
|
const fromName = account.fromName || 'GOD CRM';
|
|
|
|
// Send email
|
|
const info = await transporter.sendMail({
|
|
from: `"${fromName}" <${fromAddress}>`,
|
|
to: to,
|
|
subject: subject,
|
|
html: html
|
|
});
|
|
|
|
logger.info(`✅ Email sent successfully via ${accountLabel}: ${account.name}`);
|
|
logger.info(` Message ID: ${info.messageId}`);
|
|
|
|
return {
|
|
success: true,
|
|
messageId: info.messageId,
|
|
usedAccount: account.name,
|
|
accountType: accountLabel
|
|
};
|
|
|
|
} catch (error) {
|
|
logger.error({ err: error }, `❌ Failed to send via ${accountLabel} (${account.name})`);
|
|
|
|
// If this is not the last account, try next one
|
|
if (i < smtpAccounts.length - 1) {
|
|
logger.warn(` ⚠️ Trying next SMTP account...`);
|
|
continue;
|
|
} else {
|
|
// All accounts failed
|
|
return {
|
|
success: false,
|
|
error: `All SMTP accounts failed. Last error: ${error.message}`
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return { success: false, error: 'No SMTP accounts available' };
|
|
}
|
|
|
|
/**
|
|
* Load SMTP configuration
|
|
*/
|
|
export function loadSMTPConfig() {
|
|
try {
|
|
if (fs.existsSync(SMTP_CONFIG_FILE)) {
|
|
const data = fs.readFileSync(SMTP_CONFIG_FILE, 'utf8');
|
|
return JSON.parse(data);
|
|
}
|
|
return { accounts: [] };
|
|
} catch (error) {
|
|
logger.error({ err: error }, 'Error loading SMTP config');
|
|
return { accounts: [] };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save SMTP configuration
|
|
*/
|
|
export function saveSMTPConfig(config) {
|
|
try {
|
|
fs.writeFileSync(SMTP_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
return { success: true };
|
|
} catch (error) {
|
|
logger.error({ err: error }, 'Error saving SMTP config');
|
|
return { success: false, error: error.message };
|
|
}
|
|
}
|