MBO-Tech-IT-Webseite/lib/mailer.ts

212 lines
8.5 KiB
TypeScript
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.

import nodemailer from "nodemailer";
import { queueEmail } from "./email-queue";
// Port 587 = STARTTLS, Port 465 = SSL/TLS
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT ?? 587),
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
connectionTimeout: 15000,
greetingTimeout: 10000,
socketTimeout: 20000,
tls: {
rejectUnauthorized: false,
ciphers: "SSLv3",
},
});
export interface KontaktEmailData {
name: string;
anrede?: string;
telefon?: string;
email: string;
betreff: string;
nachricht?: string;
}
interface MailOptions {
from: string;
to: string | undefined;
replyTo?: string;
subject: string;
text: string;
html: string;
}
async function sendWithFallback(
options: MailOptions,
label: string
): Promise<{ sent: boolean; queued: boolean }> {
if (!options.to) {
console.error(`[Mailer] Kein Empfänger für "${label}" Mail übersprungen`);
return { sent: false, queued: false };
}
try {
await transporter.sendMail(options);
console.log(`[Mailer] ✓ Mail "${label}" an "${options.to}" gesendet`);
return { sent: true, queued: false };
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
console.error(`[Mailer] ✗ Mail "${label}" fehlgeschlagen (${msg}) versuche Queue`);
const queued = await queueEmail({
mail_from: options.from,
mail_to: options.to,
reply_to: options.replyTo,
subject: options.subject,
html: options.html,
body_text: options.text,
});
return { sent: false, queued };
}
}
export interface RegistrierungData {
email: string;
firma?: string;
bestaetigungsLink: string;
}
export async function sendeRegistrierungsBestaetigung(
data: RegistrierungData
): Promise<void> {
const html = `
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"></head>
<body style="font-family:system-ui,sans-serif;color:#e2e8f0;max-width:600px;margin:0 auto;padding:0">
<div style="background:#18212f;padding:20px 24px;border-bottom:2px solid #f97316">
<h1 style="color:#f97316;margin:0;font-size:20px;font-weight:700">MBO Tech IT</h1>
<p style="color:rgba(255,255,255,0.6);margin:4px 0 0;font-size:13px">Kunden-Portal</p>
</div>
<div style="padding:24px;background:#1e2a3b">
<h2 style="margin:0 0 16px;font-size:18px;color:#f8fafc">Bitte bestätigen Sie Ihre E-Mail-Adresse</h2>
<p style="color:#94a3b8;margin:0 0 24px">
${data.firma ? `Hallo ${data.firma},` : "Hallo,"}<br><br>
vielen Dank für Ihre Registrierung im MBO Tech IT Kunden-Portal.
Bitte bestätigen Sie Ihre E-Mail-Adresse, um Zugang zu Ihren IT-Anfragen zu erhalten.
</p>
<a href="${data.bestaetigungsLink}"
style="display:inline-block;background:#f97316;color:#fff;font-weight:700;padding:12px 24px;border-radius:8px;text-decoration:none;font-size:15px">
E-Mail bestätigen
</a>
<p style="color:#64748b;font-size:12px;margin:24px 0 0">
Dieser Link ist 24 Stunden gültig. Falls Sie sich nicht registriert haben, können Sie diese E-Mail ignorieren.
</p>
</div>
<div style="padding:12px 24px;background:#111925;border-top:1px solid rgba(255,255,255,0.1)">
<p style="margin:0;font-size:11px;color:#64748b">MBO Tech IT · ${process.env.APP_URL ?? "https://mbo-tech-it.de"}</p>
</div>
</body>
</html>`;
await sendWithFallback(
{
from: `"MBO Tech IT" <${process.env.SMTP_FROM}>`,
to: data.email,
subject: "Bitte bestätigen Sie Ihre E-Mail MBO Tech IT",
text: `Hallo,\n\nBitte bestätigen Sie Ihre E-Mail-Adresse:\n${data.bestaetigungsLink}\n\nDieser Link ist 24 Stunden gültig.\n\nMBO Tech IT`,
html,
},
`Registrierungsbestätigung ${data.email}`
);
}
export async function sendeAnfrageBestaetigung(data: {
name: string;
email: string;
betreff: string;
}): Promise<void> {
const html = `
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"></head>
<body style="font-family:system-ui,sans-serif;color:#e2e8f0;max-width:600px;margin:0 auto;padding:0">
<div style="background:#18212f;padding:20px 24px;border-bottom:2px solid #f97316">
<h1 style="color:#f97316;margin:0;font-size:20px;font-weight:700">MBO Tech IT</h1>
<p style="color:rgba(255,255,255,0.6);margin:4px 0 0;font-size:13px">Anfrage erhalten</p>
</div>
<div style="padding:24px;background:#1e2a3b">
<h2 style="margin:0 0 16px;font-size:18px;color:#f8fafc">Vielen Dank für Ihre Anfrage, ${data.name}!</h2>
<p style="color:#94a3b8;margin:0 0 16px;line-height:1.6">
Ihre Anfrage zum Thema <strong style="color:#f8fafc">„${data.betreff}"</strong> ist bei uns eingegangen.
Wir melden uns schnellstmöglich bei Ihnen.
</p>
<p style="color:#94a3b8;margin:0 0 24px;line-height:1.6">
Bei dringenden Anliegen erreichen Sie uns direkt unter:<br>
<a href="tel:+4917193451093" style="color:#f97316;font-weight:600">+49 171 9345193</a>
</p>
<div style="padding:12px 16px;background:#111925;border-left:3px solid #f97316;border-radius:0 4px 4px 0">
<p style="margin:0;font-size:13px;color:#64748b">Betreff: ${data.betreff}</p>
</div>
</div>
<div style="padding:12px 24px;background:#111925;border-top:1px solid rgba(255,255,255,0.1)">
<p style="margin:0;font-size:11px;color:#64748b">MBO Tech IT · <a href="${process.env.APP_URL ?? "https://mbo-tech-it.de"}" style="color:#64748b">${process.env.APP_URL ?? "https://mbo-tech-it.de"}</a></p>
</div>
</body>
</html>`;
await sendWithFallback(
{
from: `"MBO Tech IT" <${process.env.SMTP_FROM}>`,
to: data.email,
subject: `Ihre Anfrage ist eingegangen MBO Tech IT`,
text: `Hallo ${data.name},\n\nvielen Dank für Ihre Anfrage zum Thema „${data.betreff}". Wir melden uns schnellstmöglich bei Ihnen.\n\nBei dringenden Anliegen erreichen Sie uns unter: +49 171 9345193\n\nMBO Tech IT\n${process.env.APP_URL ?? "https://mbo-tech-it.de"}`,
html,
},
`Anfragebestätigung ${data.email}`
);
}
export async function sendeKontaktEmail(
data: KontaktEmailData
): Promise<{ sent: boolean; queued: boolean }> {
const anrede = data.anrede
? `${data.anrede.charAt(0).toUpperCase() + data.anrede.slice(1)} `
: "";
const html = `
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"></head>
<body style="font-family:system-ui,sans-serif;color:#e2e8f0;max-width:600px;margin:0 auto;padding:0">
<div style="background:#18212f;padding:20px 24px;border-bottom:2px solid #f97316">
<h1 style="color:#f97316;margin:0;font-size:20px;font-weight:700">MBO Tech IT</h1>
<p style="color:rgba(255,255,255,0.6);margin:4px 0 0;font-size:13px">Neue Kontaktanfrage</p>
</div>
<div style="padding:24px;background:#1e2a3b">
<h2 style="margin:0 0 16px;font-size:18px;color:#f8fafc">Kontaktanfrage von ${anrede}${data.name}</h2>
<table style="width:100%;border-collapse:collapse;margin-bottom:24px">
<tr><td style="padding:6px 0;color:#94a3b8;width:120px">Name</td><td style="padding:6px 0;font-weight:600;color:#f8fafc">${anrede}${data.name}</td></tr>
${data.telefon ? `<tr><td style="padding:6px 0;color:#94a3b8">Telefon</td><td style="padding:6px 0"><a href="tel:${data.telefon}" style="color:#f97316">${data.telefon}</a></td></tr>` : ""}
<tr><td style="padding:6px 0;color:#94a3b8">E-Mail</td><td style="padding:6px 0"><a href="mailto:${data.email}" style="color:#60a5fa">${data.email}</a></td></tr>
<tr><td style="padding:6px 0;color:#94a3b8">Betreff</td><td style="padding:6px 0;color:#f8fafc">${data.betreff}</td></tr>
</table>
${
data.nachricht
? `<div style="padding:12px 16px;background:#111925;border-left:3px solid #f97316"><p style="margin:0;font-size:14px;white-space:pre-wrap;color:#cbd5e1">${data.nachricht}</p></div>`
: ""
}
</div>
<div style="padding:12px 24px;background:#111925;border-top:1px solid rgba(255,255,255,0.1)">
<p style="margin:0;font-size:11px;color:#64748b">MBO Tech IT · ${process.env.APP_URL ?? "https://mbo-tech-it.de"}</p>
</div>
</body>
</html>`;
return sendWithFallback(
{
from: `"MBO Tech IT" <${process.env.SMTP_FROM}>`,
to: process.env.SMTP_TO,
replyTo: data.email,
subject: `Kontaktanfrage: ${anrede}${data.name} ${data.betreff}`,
text: `Neue Kontaktanfrage\n\nName: ${anrede}${data.name}${data.telefon ? `\nTelefon: ${data.telefon}` : ""}\nE-Mail: ${data.email}\nBetreff: ${data.betreff}${data.nachricht ? `\n\nNachricht:\n${data.nachricht}` : ""}`,
html,
},
`Kontaktanfrage ${data.name}`
);
}