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
This commit is contained in:
68
server/utils/mailer.mjs
Normal file
68
server/utils/mailer.mjs
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user