Tutoriál
Odesílání e-mailů z Nuxtu
Odesílejte e-maily ze serverové API routy v Nuxtu přes Node.js SDK Emailitu, držte klíč v privátním runtimeConfig a ověřujte webhooky pomocí h3.
Tento návod ukazuje, jak odesílat e-maily z aplikace v Nuxtu 3. Emailit voláte ze serverové API routy, API klíč držíte v privátním runtimeConfig a webhooky ověřujete pomocnými funkcemi h3.
Předpoklady
- Nuxt 3 se serverovým presetem pro Node.js 18 nebo novější.
- Ověřená odesílací doména, například
acme.com. - API klíč. Stačí klíč jen pro odesílání omezený na vaši doménu.
- Dokud váš workspace nemá produkční přístup, můžete odesílat jen na e-mailové adresy účtů členů workspace.
Nainstalujte SDK
npm install @emailit/nodeNastavte API klíč
Deklarujte privátní klíče konfigurace runtime. Klíče mimo public jsou dostupné jen na serveru:
export default defineNuxtConfig({
runtimeConfig: {
emailitApiKey: '',
emailitWebhookSecret: '',
},
});Nuxt je vyplní z proměnných prostředí s předponou NUXT_:
NUXT_EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
NUXT_EMAILIT_WEBHOOK_SECRET=whsec_••••••••Přidejte malou pomocnou funkci. Soubory v server/utils se v serverových routách importují automaticky:
import type { H3Event } from 'h3';
import { Emailit } from '@emailit/node';
export function emailitClient(event: H3Event) {
return new Emailit(useRuntimeConfig(event).emailitApiKey);
}Pokud TypeScript hlásí chybějící deklaraci pro @emailit/node, přidejte do svého projektu soubor .d.ts s declare module '@emailit/node';.
Odešlete e-mail
Vytvořte serverovou API routu. Tato routa kontaktního formuláře odesílá na pevnou interní adresu, takže ji návštěvníci nemohou zneužít k posílání e-mailů komukoli:
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 };
});Ze stránky nebo komponenty ji volejte pomocí $fetch:
<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>Pokud chcete místo obsahu přímo v požadavku odeslat uloženou šablonu, předejte template (alias nebo ID tem_) a variables. Viz Šablony a Odeslání e-mailu.
Odesílání přes SMTP
Pokud dáváte přednost SMTP, použijte Nodemailer v serverové routě. SMTP potřebuje serverový preset pro Node.js; presety pro edge a workery nemohou otevírat SMTP spojení, takže tam použijte 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 },
});
}Pak z routy zavolejte await mailer().sendMail({ from, to, subject, html }). Další porty najdete na stránce Nastavení SMTP.
Přijímejte webhooky
Vytvořte webhook, který míří na https://your-app.com/api/webhooks/emailit. Ověřte podpis vůči surovému tělu požadavku a pak zpracujte pole událostí:
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 };
});Do 30 sekund vraťte 2xx; při jiných odpovědích se požadavek opakuje. Viz Ověření podpisu webhooků.
Tipy pro produkční provoz
- Tajné údaje nastavte u hostingu.
NUXT_EMAILIT_API_KEYnastavte v proměnných prostředí u svého poskytovatele hostingu, místo abyste nasazovali soubor.env. - Před odesláním validujte. Příjemce z prohlížeče přijímejte, jen když jde o vlastní adresu přihlášeného uživatele, a u veřejných rout omezte rychlost. Každý e-mail stojí kredity a počítá se do vašich limitů odesílání.
- Pro každé prostředí používejte samostatný klíč, abyste mohli odvolat klíč pro náhledy, aniž byste sahali na produkci.