Tutorial
Enviar e-mails com Nuxt
Envie e-mails de uma rota de API do servidor do Nuxt com o SDK de Node.js do Emailit, mantenha a chave no runtimeConfig privado e verifique webhooks com o h3.
Este guia mostra como enviar e-mails de uma aplicação Nuxt 3. Você chama o Emailit a partir de uma rota de API do servidor, mantém a chave de API no runtimeConfig privado e verifica os webhooks com os helpers do h3.
Pré-requisitos
- Nuxt 3 com um preset de servidor Node.js 18+.
- Um domínio de envio verificado, por exemplo,
acme.com. - Uma chave de API. Uma chave Sending Only restrita ao seu domínio é suficiente.
- Até o seu workspace ter acesso de produção, você só pode enviar para os e-mails das contas dos membros do workspace.
Instalar o SDK
npm install @emailit/nodeConfigurar a chave de API
Declare chaves privadas no runtime config. As chaves fora de public só ficam disponíveis no servidor:
export default defineNuxtConfig({
runtimeConfig: {
emailitApiKey: '',
emailitWebhookSecret: '',
},
});O Nuxt as preenche a partir de variáveis de ambiente com o prefixo NUXT_:
NUXT_EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
NUXT_EMAILIT_WEBHOOK_SECRET=whsec_••••••••Adicione um pequeno helper. Os arquivos em server/utils são importados automaticamente nas rotas do servidor:
import type { H3Event } from 'h3';
import { Emailit } from '@emailit/node';
export function emailitClient(event: H3Event) {
return new Emailit(useRuntimeConfig(event).emailitApiKey);
}Se o TypeScript acusar a falta de uma declaração para @emailit/node, adicione declare module '@emailit/node'; a um arquivo .d.ts do seu projeto.
Enviar um e-mail
Crie uma rota de API do servidor. Esta rota de formulário de contato envia para um endereço interno fixo, então os visitantes não podem usá-la para enviar e-mails a qualquer pessoa:
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 };
});Chame-a a partir de uma página ou de um componente com $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>Para enviar um template salvo em vez de conteúdo inline, passe template (um alias ou um ID tem_) e variables. Consulte Templates e Enviar um e-mail.
Enviar por SMTP como alternativa
Se você preferir SMTP, use o Nodemailer em uma rota do servidor. O SMTP exige um preset de servidor Node.js; os presets de edge e de workers não conseguem abrir conexões SMTP, então use a API nesses casos.
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 },
});
}Depois, chame await mailer().sendMail({ from, to, subject, html }) a partir de uma rota. Consulte Configurações de SMTP para as outras portas.
Receber webhooks
Crie um webhook que aponte para https://your-app.com/api/webhooks/emailit. Verifique a assinatura com base no corpo bruto e depois interprete o array de eventos:
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 };
});Retorne um 2xx em até 30 segundos; as outras respostas recebem novas tentativas. Consulte Assinatura das requisições.
Dicas para produção
- Defina os segredos na sua hospedagem. Configure
NUXT_EMAILIT_API_KEYnas configurações de ambiente do seu provedor de hospedagem em vez de publicar um arquivo.env. - Valide antes de enviar. Só aceite um destinatário vindo do navegador quando for o próprio endereço do usuário conectado e limite a taxa de requisições das rotas públicas. Cada e-mail custa créditos e conta para os seus limites de envio.
- Use chaves separadas por ambiente para poder revogar uma chave de preview sem mexer na produção.