Files
Emailsorter/server/utils/mailer.mjs
ANDJ ecae89a79d fix(dev): Vite-API-Proxy, Auth, Stripe-Mails und Backend-Erweiterungen
- Client: API-Basis-URL (joinApiUrl, /v1-Falle), Vite strictPort + Proxy 127.0.0.1, Nicht-JSON-Fehler

- Server: /api-404 ohne Wildcard-Bug, SPA-Fallback, Auth-Middleware, Cron, Mailer, Crypto

- Routen: OAuth-State, Email/Stripe/Analytics; client/.env.example

Made-with: Cursor
2026-04-03 00:23:01 +02:00

69 lines
1.8 KiB
JavaScript

/**
* Plain SMTP mailer (nodemailer). Optional: if SMTP not configured, send is a no-op.
*/
import nodemailer from 'nodemailer'
import { readFileSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
import { log } from '../middleware/logger.mjs'
const __dirname = dirname(fileURLToPath(import.meta.url))
let transporter = null
function getTransporter() {
const host = process.env.SMTP_HOST
const user = process.env.SMTP_USER
const pass = process.env.SMTP_PASS
if (!host || !user || !pass) {
return null
}
if (!transporter) {
transporter = nodemailer.createTransport({
host,
port: parseInt(process.env.SMTP_PORT || '587', 10),
secure: process.env.SMTP_SECURE === 'true',
auth: { user, pass },
})
}
return transporter
}
export function renderTemplate(text, vars) {
let out = text
for (const [k, v] of Object.entries(vars || {})) {
out = out.split(`{{${k}}}`).join(v != null ? String(v) : '')
}
return out
}
export function loadEmailTemplate(name) {
const path = join(__dirname, '..', 'emails', `${name}.txt`)
return readFileSync(path, 'utf8')
}
/**
* Send plain-text email. Returns false if SMTP not configured or send failed (logged).
*/
export async function sendPlainEmail({ to, subject, text }) {
const from = process.env.SMTP_FROM || process.env.SMTP_USER
if (!to || !subject || !text) {
log.warn('sendPlainEmail: missing to/subject/text')
return false
}
const tx = getTransporter()
if (!tx) {
log.warn('SMTP not configured (SMTP_HOST/SMTP_USER/SMTP_PASS); email skipped')
return false
}
try {
await tx.sendMail({ from, to, subject, text })
log.info(`Email sent to ${to}: ${subject}`)
return true
} catch (e) {
log.error('sendPlainEmail failed', { error: e.message, to })
return false
}
}