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)
58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
// 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}`,
|
||
});
|
||
}
|
||
}
|