Tutorial
E-Mails mit Nuxt senden
Senden Sie E-Mails aus einer Server-API-Route von Nuxt mit dem Node.js-SDK von Emailit, halten Sie den Schlüssel in der privaten runtimeConfig und verifizieren Sie Webhooks mit h3.
Diese Anleitung zeigt, wie Sie E-Mails aus einer Nuxt-3-App senden. Sie rufen Emailit aus einer Server-API-Route auf, halten den API-Schlüssel in der privaten runtimeConfig und verifizieren Webhooks mit Hilfsfunktionen von h3.
Voraussetzungen
- Nuxt 3 mit einem Server-Preset für Node.js 18 oder neuer.
- Eine verifizierte Versanddomain, zum Beispiel
acme.com. - Ein API-Schlüssel. Ein reiner Sende-Schlüssel, der auf Ihre Domain beschränkt ist, genügt.
- Solange Ihr Workspace keinen Produktionszugang hat, können Sie nur an die Konto-E-Mail-Adressen von Workspace-Mitgliedern senden.
SDK installieren
npm install @emailit/nodeAPI-Schlüssel konfigurieren
Deklarieren Sie private Schlüssel in der Runtime-Konfiguration. Schlüssel außerhalb von public sind nur auf dem Server verfügbar:
export default defineNuxtConfig({
runtimeConfig: {
emailitApiKey: '',
emailitWebhookSecret: '',
},
});Nuxt befüllt sie aus Umgebungsvariablen mit dem Präfix NUXT_:
NUXT_EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
NUXT_EMAILIT_WEBHOOK_SECRET=whsec_••••••••Fügen Sie eine kleine Hilfsfunktion hinzu. Dateien in server/utils werden in Server-Routen automatisch importiert:
import type { H3Event } from 'h3';
import { Emailit } from '@emailit/node';
export function emailitClient(event: H3Event) {
return new Emailit(useRuntimeConfig(event).emailitApiKey);
}Wenn TypeScript eine fehlende Deklaration für @emailit/node meldet, fügen Sie declare module '@emailit/node'; in eine .d.ts-Datei in Ihrem Projekt ein.
E-Mail senden
Erstellen Sie eine Server-API-Route. Diese Route für ein Kontaktformular sendet an eine feste interne Adresse, sodass Besucher sie nicht nutzen können, um beliebigen Personen E-Mails zu schicken:
export default defineEventHandler(async (event) => {
const { email, message } = await readBody(event);
if (typeof email !== 'string' || typeof message !== 'string' || !email.includes('@')) {
throw createError({ statusCode: 400, statusMessage: 'Invalid input' });
}
const sent = await emailitClient(event).emails.send({
from: 'Acme website <website@acme.com>',
to: 'support@acme.com',
reply_to: email,
subject: 'New contact form message',
text: message,
});
return { id: sent.id };
});Rufen Sie sie aus einer Seite oder Komponente mit $fetch auf:
<script setup lang="ts">
const email = ref('');
const message = ref('');
const sent = ref(false);
async function submit() {
await $fetch('/api/contact', {
method: 'POST',
body: { email: email.value, message: message.value },
});
sent.value = true;
}
</script>
<template>
<form @submit.prevent="submit">
<input v-model="email" type="email" required />
<textarea v-model="message" required />
<button type="submit">Send</button>
<p v-if="sent">Thanks, we'll be in touch.</p>
</form>
</template>Um statt Inline-Inhalt eine gespeicherte Vorlage zu senden, übergeben Sie template (einen Alias oder eine tem_-ID) und variables. Siehe Vorlagen und E-Mail senden.
Alternativ per SMTP senden
Wenn Sie SMTP bevorzugen, verwenden Sie Nodemailer in einer Server-Route. SMTP erfordert ein Node.js-Server-Preset; Edge- und Worker-Presets können keine SMTP-Verbindungen öffnen, verwenden Sie dort also die API.
import nodemailer from 'nodemailer';
export function mailer() {
return nodemailer.createTransport({
host: 'smtp.emailit.com',
port: 587,
secure: false,
requireTLS: true,
auth: { user: 'emailit', pass: useRuntimeConfig().emailitApiKey },
});
}Rufen Sie dann in einer Route await mailer().sendMail({ from, to, subject, html }) auf. Weitere Ports finden Sie unter SMTP-Einstellungen.
Webhooks empfangen
Erstellen Sie einen Webhook, der auf https://your-app.com/api/webhooks/emailit zeigt. Verifizieren Sie die Signatur anhand des unveränderten Bodys und parsen Sie dann das Array der Events:
import { createHmac, timingSafeEqual } from 'node:crypto';
export default defineEventHandler(async (event) => {
const rawBody = (await readRawBody(event)) ?? '';
const signature = getHeader(event, 'x-emailit-signature') ?? '';
const timestamp = getHeader(event, 'x-emailit-timestamp') ?? '';
const secret = useRuntimeConfig(event).emailitWebhookSecret;
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
const valid =
Number.isFinite(age) &&
age <= 300 &&
expected.length === signature.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
if (!valid) {
throw createError({ statusCode: 401, statusMessage: 'Invalid signature' });
}
const events = JSON.parse(rawBody) as Array<{ event_id: string; type: string; data: { object: any } }>;
for (const item of events) {
if (item.type === 'email.complained') {
// Stop emailing item.data.object.to
}
}
return { received: events.length };
});Geben Sie innerhalb von 30 Sekunden einen 2xx-Status zurück; bei anderen Antworten wird die Anfrage wiederholt. Siehe Anfragesignatur.
Tipps für den Produktivbetrieb
- Secrets beim Hoster hinterlegen. Konfigurieren Sie
NUXT_EMAILIT_API_KEYin den Umgebungseinstellungen Ihres Hosting-Anbieters, statt eine.env-Datei auszuliefern. - Vor dem Senden validieren. Übernehmen Sie einen Empfänger nur dann aus dem Browser, wenn es die eigene Adresse des angemeldeten Nutzers ist, und begrenzen Sie die Anfragerate öffentlicher Routen. Jede E-Mail kostet Credits und zählt gegen Ihre Versandlimits.
- Getrennte Schlüssel pro Umgebung verwenden, damit Sie einen Preview-Schlüssel widerrufen können, ohne die Produktion zu berühren.