import nodemailer from 'nodemailer' import { config } from '../config.js' let transporter = null function getTransporter() { if (!config.smtp.host || !config.smtp.user) return null if (!transporter) { transporter = nodemailer.createTransport({ host: config.smtp.host, port: config.smtp.port, secure: config.smtp.secure, auth: { user: config.smtp.user, pass: config.smtp.pass }, }) } return transporter } // Throttle: pro Kunde maximal eine Benachrichtigung je Zeitfenster, // damit ein aktiver Chat nicht pro Nachricht eine Mail ausloest. const lastNotifyByCustomer = new Map() // customerId -> timestamp /** * Benachrichtigt die Admins per E-Mail ueber eine neue Portal-Chatnachricht. * Fehler werden nur geloggt - der Chat darf am Mailversand nie scheitern. */ export async function sendChatNotification(customer, text) { try { const mailer = getTransporter() if (!mailer || !config.chatNotify.emails.length) return { sent: false, reason: 'nicht konfiguriert' } const now = Date.now() const last = lastNotifyByCustomer.get(customer.$id) || 0 const throttleMs = config.chatNotify.throttleMin * 60 * 1000 if (now - last < throttleMs) return { sent: false, reason: 'throttled' } lastNotifyByCustomer.set(customer.$id, now) const name = customer.name || customer.email || 'Kunde' await mailer.sendMail({ from: `"Webklar Kundenportal" <${config.smtp.from}>`, to: config.chatNotify.emails.join(', '), subject: `Neue Portalnachricht von ${name}`, text: [ `${name} hat im Kundenportal geschrieben:`, '', text, '', 'Antworten: https://project.webklar.com/admin.html (Tab Chat)', ].join('\n'), }) return { sent: true } } catch (err) { console.error('[mailer] Chat-Benachrichtigung fehlgeschlagen:', err.message) return { sent: false, reason: err.message } } } // --------------------------------------------------------------------------- // Wartungs-Abo: Vertrags-/Kuendigungs-/Widerrufsbestaetigungen // --------------------------------------------------------------------------- /** Mail an die Webklar-Admins (Abo-Ereignisse). Fehler werden nur geloggt. */ export async function sendAdminNotice(subject, lines) { try { const mailer = getTransporter() if (!mailer || !config.chatNotify.emails.length) return { sent: false, reason: 'nicht konfiguriert' } await mailer.sendMail({ from: `"Webklar Kundenportal" <${config.smtp.from}>`, to: config.chatNotify.emails.join(', '), subject: `[Abo] ${subject}`, text: lines.join('\n'), }) return { sent: true } } catch (err) { console.error('[mailer] Admin-Hinweis fehlgeschlagen:', err.message) return { sent: false, reason: err.message } } } /** * Mail an Kunden. `attachments` fuer die Vertragsbestaetigung auf dauerhaftem * Datentraeger (ยง 312f BGB): Bedingungen als HTML-Anhang. * Ergebnis: nodemailer-Info (messageId, Antwort des Mailservers, abgelehnte Empfaenger). */ export async function sendCustomerMail(to, subject, lines, attachments = []) { const mailer = getTransporter() if (!mailer) throw new Error('SMTP nicht konfiguriert') return mailer.sendMail({ from: `"Webklar" <${config.smtp.from}>`, to, bcc: config.chatNotify.emails.join(', ') || undefined, subject, text: lines.join('\n'), attachments, }) }