chahinebrini bdfcc40a6c feat(auth-hook): send-email hook for dynamic sender-name + i18n subject
GoTrue-Send-Email-Hook (v2.155+) → backend rendert Mails selbst, schickt
via Brevo Transactional API. Vorteil: pro Mail-Typ × Locale eigener
Sender-Display-Name UND Subject (GoTrue's eingebauter Mailer ist global
statisch).

Files:
- backend/server/utils/mail/templates.ts — 5 mail-types × 4 locales
  Sender-Name, Subject, Title, Body, HelpText, Privacy-Label.
  HTML-Renderer mit Nunito + Icon + DSGVO-Footer (analog public/templates).
- backend/server/utils/mail/brevo.ts — Brevo Transactional API client
  (POST /v3/smtp/email, separate REST-API-Key vom SMTP-Key)
- backend/server/api/auth-hooks/send-email.post.ts — Endpoint mit
  Standard-Webhooks Signature-Verify (HMAC-SHA256, timing-safe compare,
  multi-secret-rotation support)
- backend/nitro.config.ts — runtimeConfig: brevoApiKey,
  hookSendEmailSecrets, mailSenderEmail

Requires (außerhalb dieses commits):
- Infisical staging: BREVO_API_KEY (✓), HOOK_SEND_EMAIL_SECRETS (✓)
- docker-compose: GOTRUE_HOOK_SEND_EMAIL_{ENABLED,URI,SECRETS} (✓)
- GoTrue upgrade v2.154 → v2.189 (✓, mit auth.factor_type owner-transfer)
2026-05-19 18:04:14 +02:00

58 lines
1.4 KiB
TypeScript
Raw Permalink 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.

// Brevo Transactional API Client.
// Genutzt vom Auth-Hook (send-email.post.ts) für dynamic Sender-Name +
// Subject pro Mail-Typ × Locale. Replaces GoTrue's eingebauten SMTP-Sender.
import type { H3Event } from 'h3';
const BREVO_API_URL = 'https://api.brevo.com/v3/smtp/email';
interface BrevoSendParams {
to: string;
subject: string;
senderName: string;
senderEmail: string;
htmlContent: string;
}
export async function sendBrevoMail(
event: H3Event,
params: BrevoSendParams,
): Promise<void> {
const config = useRuntimeConfig(event);
const apiKey = config.brevoApiKey as string;
if (!apiKey) {
throw createError({
statusCode: 500,
message: 'BREVO_API_KEY not configured',
});
}
const body = {
sender: { name: params.senderName, email: params.senderEmail },
to: [{ email: params.to }],
subject: params.subject,
htmlContent: params.htmlContent,
};
const res = await fetch(BREVO_API_URL, {
method: 'POST',
headers: {
'api-key': apiKey,
accept: 'application/json',
'content-type': 'application/json',
},
body: JSON.stringify(body),
});
if (!res.ok) {
const errText = await res.text().catch(() => '');
console.error(
`[brevo] send failed status=${res.status} to=${params.to} body=${errText.slice(0, 300)}`,
);
throw createError({
statusCode: 502,
message: `Brevo API error ${res.status}`,
});
}
}