/** Serverseitiger E-Mail-Versand über die Portal-Mail-API (mp-mail-api).
*
* Fire-and-forget: Ein Fehler (Mail-API down, Relay-Fehler) beeinträchtigt
* die auslösende Portal-Aktion nie. Die Mail-API selbst puffert im Fehlerfall
* in ihrer Outbox und versucht es erneut.
*
* Gestaltung wie im Schulportal: HTML-Karte (600 px, Kopfzeile in Portal-Farben,
* Zeilen-Tabelle, optional Status-Box/Zitat/Aktions-Button) plus Plain-Text-
* Fallback, immer beide an die Mail-API (sendet multipart/alternative).
*/
const MAIL_API_URL = process.env.MAIL_API_URL || '' // z. B. http://mp-mail-api:8080
const MAIL_API_TOKEN = process.env.MAIL_API_TOKEN || ''
const PORTAL_URL = process.env.PORTAL_URL || 'https://mieterportal.hocks.eu'
// Portal-Farben (Hinterstein): dunkles Petrol + Amber-Akzent (vgl. Login-Seite)
const FARBE_KOPF = '#22333b' // Dunkel-Petrol
const FARBE_KOPF_ZEILE = '#fcd34d' // Amber-200 (Kicker-Zeile)
const FARBE_UNTERTITEL = '#cbd5e1'
const FARBE_BUTTON = '#f59e0b' // Amber-500
const FARBE_BUTTON_TEXT = '#1c1917'
const HINTERGRUND = '#f1f5f9'
const KARTE = '#ffffff'
const TEXT = '#0f172a'
const TEXT_SOFT = '#64748b'
const RAND = '#e2e8f0'
const FUSSZEILE_TEXT =
'— Automatische Benachrichtigung aus dem Mieterportal der Hinterstein Immobilien'
function htmlEscape(s) {
return String(s)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
}
/** Baut die HTML-Karte im Schulportal-Stil. Alle Inhalte werden escaped. */
function baueHtmlMail(opts) {
const { titel, untertitel = '', einleitung = '', zeilen = [], statusBox, zitat, aktionenHtml = '', fussnote = '' } = opts
const zeilenHtml = zeilen
.map(
([label, wert]) => `
| ${htmlEscape(label)} |
${htmlEscape(wert)} |
`,
)
.join('')
const statusHtml = statusBox
? `
${htmlEscape(statusBox.text)}
`
: ''
const zitatHtml = zitat
? `
${htmlEscape(zitat)}
`
: ''
const fussnotenHtml = fussnote
? `${htmlEscape(fussnote)}
`
: ''
return `
${htmlEscape(titel)}
${htmlEscape(einleitung || titel)}
|
Hinterstein Immobilien
${htmlEscape(titel)}
${untertitel ? `${htmlEscape(untertitel)} ` : ''}
|
|
${einleitung ? ` ${htmlEscape(einleitung)} ` : ''}
${statusHtml}
${zitatHtml}
${aktionenHtml}
${fussnotenHtml}
|
|
Hinterstein Immobilien (Demo) · mieterportal.hocks.eu Diese E-Mail wurde automatisch vom Mieterportal erzeugt. Bitte antworten Sie nicht direkt – nutzen Sie das Nachrichten-Modul im Portal.
|
|
`
}
/** Aktions-Button (portal-interne Links). */
function buttonHtml(text, url) {
return `${htmlEscape(text)}
`
}
async function sendeMail(an, betreff, text, html, cc) {
if (!MAIL_API_URL || !MAIL_API_TOKEN || !an) return
try {
const res = await fetch(`${MAIL_API_URL}/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Token': MAIL_API_TOKEN },
body: JSON.stringify({
to: an, subject: betreff, text: `${text}\n\n${FUSSZEILE_TEXT}`,
...(html ? { html } : {}),
...(cc ? { cc } : {}), // v1.22: Komma-getrennte CC-Empfänger
}),
})
if (!res.ok) console.warn(`[mail] Versand an ${an} fehlgeschlagen: HTTP ${res.status}`)
} catch (e) {
console.warn(`[mail] Versand an ${an} fehlgeschlagen:`, e.message)
}
}
/** E-Mail-Adressen aller aktiven Verwaltungsnutzer (komma-getrennt, für CC). */
async function verwaltungEmails() {
const { rows } = await require('./db').pool.query(
`SELECT email FROM users WHERE rolle = 'verwaltung' AND aktiv AND email <> ''`,
)
return rows.map((r) => r.email).join(', ')
}
/** Alle aktiven Verwaltungsnutzer benachrichtigen. */
async function benachrichtigeVerwaltung(betreff, text, html) {
const { rows } = await require('./db').pool.query(
`SELECT email FROM users WHERE rolle = 'verwaltung' AND aktiv AND email <> ''`,
)
for (const r of rows) sendeMail(r.email, betreff, text, html)
}
/** Mieter einer bestimmten Wohnung benachrichtigen. */
async function benachrichtigeMieter(einheitId, betreff, text, html) {
const { rows } = await require('./db').pool.query(
`SELECT email FROM users WHERE rolle = 'mieter' AND aktiv AND einheit_id = $1 AND email <> ''`,
[einheitId],
)
for (const r of rows) sendeMail(r.email, betreff, text, html)
}
function einheitLabel(u) {
return u ? `${u.building}, Whg. ${u.number}` : ''
}
module.exports = {
sendeMail,
benachrichtigeVerwaltung,
benachrichtigeMieter,
verwaltungEmails,
einheitLabel,
baueHtmlMail,
buttonHtml,
}