Files
MC_Report/backend/mailer.js
canglan 8c5ce78fd0 chore: add AGPLv3 copyright header to all source files
- 52 JS files (backend + public/js): header with
  Copyright (C) 2026 Sea Network Technology Studio
  Author: CangLan <admin@sea-studio.top>
  + AGPLv3 notice
- idempotent (skips if header present), all syntax-checked
2026-08-19 20:27:05 +08:00

97 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* MC Report System
* Copyright (C) 2026 Sea Network Technology Studio
* Author: CangLan <admin@sea-studio.top>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const nodemailer = require('nodemailer');
const { getPool, query, getRow, getConfig } = require('./db');
const { logEmail, logSystem } = require('./logger');
async function getSmtpConfig() {
try {
const rows = await query("SELECT k, v FROM settings WHERE k LIKE 'smtp_%'");
const cfg = {};
for (const r of rows) cfg[r.k] = r.v;
return {
host: cfg.smtp_host || '',
port: parseInt(cfg.smtp_port) || 587,
secure: cfg.smtp_secure === '1',
user: cfg.smtp_user || '',
pass: cfg.smtp_pass || '',
from: cfg.smtp_from || 'noreply@example.com',
};
} catch { return { host: '', port: 587, secure: false, user: '', pass: '', from: '' }; }
}
async function getSiteName() {
const row = await getRow("SELECT v FROM settings WHERE k = 'site_name'");
return row ? row.v : 'MC举报系统';
}
async function getSiteUrl() {
const row = await getRow("SELECT v FROM settings WHERE k = 'site_url'");
return row ? row.v : 'http://localhost:3100';
}
async function getTemplate(code) {
return getRow('SELECT * FROM email_templates WHERE code = ?', [code]);
}
function renderTemplate(template, vars) {
let { subject, body } = template;
for (const [k, v] of Object.entries(vars)) {
const re = new RegExp(`\\{\\{${k}\\}\\}`, 'g');
const val = String(v ?? '');
subject = subject.replace(re, () => val);
body = body.replace(re, () => val);
}
return { subject, body };
}
let _transporter = null;
let _transporterKey = '';
function getTransporter(cfg) {
const key = `${cfg.host}:${cfg.port}:${cfg.user}`;
if (_transporter && _transporterKey === key) return _transporter;
_transporterKey = key;
_transporter = nodemailer.createTransport({ host: cfg.host, port: cfg.port, secure: cfg.secure, auth: { user: cfg.user, pass: cfg.pass } });
return _transporter;
}
async function sendEmail(to, templateCode, vars) {
try {
const cfg = await getSmtpConfig();
if (!cfg.host || !cfg.user) { console.log('[Mailer] SMTP未配置'); await logSystem('warn', 'mailer', 'SMTP未配置邮件未发送', { to, template: templateCode }); return false; }
const template = await getTemplate(templateCode);
if (!template) { console.log('[Mailer] 模板不存在:', templateCode); await logEmail(to, templateCode, '', 'failed', '模板不存在: ' + templateCode); return false; }
const siteName = await getSiteName();
const allVars = { ...vars, site_name: siteName, site_url: await getSiteUrl() };
const { subject, body } = renderTemplate(template, allVars);
const transporter = getTransporter(cfg);
await transporter.sendMail({ from: `"${siteName}" <${cfg.from}>`, to, subject, html: body });
await logEmail(to, templateCode, subject, 'sent');
return true;
} catch (err) {
console.error('[Mailer]', err.message);
await logEmail(to, templateCode, '', 'failed', err.message);
return false;
}
}
module.exports = { sendEmail, renderTemplate, getTemplate, getSmtpConfig, getSiteName, getSiteUrl };