# Enviar e-mails com Next.js

> Envie e-mails de route handlers e server actions do Next.js com o SDK de Node.js do Emailit, mantenha a chave de API no servidor e verifique webhooks.

Este guia mostra como enviar e-mails de uma aplicação Next.js com o SDK `@emailit/node`, tanto a partir de um route handler quanto de uma server action, e como verificar os webhooks do Emailit. Os exemplos usam o App Router; o Pages Router é abordado no fim da seção de envio.

## Pré-requisitos

- Next.js 14 ou mais recente. O SDK exige Node.js 18 ou mais recente.
- Um [domínio de envio verificado](/pt/docs/domains/add-a-domain/), por exemplo, `acme.com`.
- Uma [chave de API](/pt/docs/developers/api-keys/). Uma chave Sending Only restrita ao seu domínio é suficiente.
- Até o seu workspace ter [acesso de produção](/pt/docs/workspaces/production-access/), você só pode enviar para os e-mails das contas dos membros do workspace.

## Instalar o SDK

```bash
npm install @emailit/node server-only
```

`server-only` faz o build falhar se um client component importar o módulo que guarda a sua chave.

## Configurar a chave de API

Adicione a chave ao `.env.local` para desenvolvimento e às variáveis de ambiente da sua hospedagem (por exemplo, as configurações do projeto na Vercel) para produção:

```bash title=".env.local"
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
EMAILIT_WEBHOOK_SECRET=whsec_••••••••
```

> **Nunca exponha a chave ao navegador:** Não use o prefixo `NEXT_PUBLIC_` nessas variáveis e não chame o Emailit a partir de client components. Tudo o que tem o prefixo `NEXT_PUBLIC_` é incluído no bundle de JavaScript que qualquer visitante pode ler.

Crie um único cliente em um módulo exclusivo do servidor:

```typescript title="lib/emailit.ts"

```

O SDK ainda não tem declarações de TypeScript. Se o compilador reclamar, adicione um arquivo de declaração:

```typescript title="types/emailit.d.ts"
declare module '@emailit/node';
```

## Enviar a partir de um route handler

Um route handler é o lugar certo para envios disparados pelo seu próprio frontend ou por outros serviços. Este handler de formulário de contato envia para um endereço interno fixo, então os visitantes não podem usá-lo para enviar e-mails a qualquer pessoa:

```typescript title="app/api/contact/route.ts"

  const { email, message } = await request.json();

  if (typeof email !== 'string' || typeof message !== 'string' || !email.includes('@')) {
    return Response.json({ error: 'Invalid input' }, { status: 400 });
  }

  try {
    const sent = await emailit.emails.send({
      from: 'Acme website <website@acme.com>',
      to: 'support@acme.com',
      reply_to: email,
      subject: 'New contact form message',
      text: message,
    });
    return Response.json({ id: sent.id });
  } catch (error) {
    console.error(error);
    return Response.json({ error: 'Could not send the message' }, { status: 502 });
  }
}
```

Chame-o a partir do navegador com `fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) })`. A chave nunca sai do servidor.

## Enviar a partir de uma server action

As server actions são executadas no servidor, então podem usar o cliente diretamente:

```typescript title="app/signup/actions.ts"
'use server';

  const email = formData.get('email');
  if (typeof email !== 'string' || !email.includes('@')) return;

  // Create the account here, then send the welcome email.
  await emailit.emails.send({
    from: 'Acme <hello@acme.com>',
    to: email,
    template: 'welcome',
    variables: { email },
  });
}
```

```tsx title="app/signup/page.tsx"

  return (
    <form action={signUp}>
      <input type="email" name="email" required />
      <button type="submit">Create account</button>
    </form>
  );
}
```

`template` recebe o alias ou o ID `tem_` de um template; consulte [Templates](/pt/docs/templates/). As server actions são endpoints públicos, então valide a entrada e adicione a sua proteção habitual contra bots e abusos antes de enviar.

### Pages Router

Com o Pages Router, envie a partir de uma API route:

```typescript title="pages/api/contact.ts"

  if (req.method !== 'POST') return res.status(405).end();
  const sent = await emailit.emails.send({
    from: 'Acme website <website@acme.com>',
    to: 'support@acme.com',
    subject: 'New contact form message',
    text: String(req.body.message ?? ''),
  });
  res.status(200).json({ id: sent.id });
}
```

## Enviar por SMTP como alternativa

Se você já usa o Nodemailer, configure-o com o relay do Emailit dentro de um route handler ou de uma server action (o SMTP exige o runtime Node.js, não o runtime Edge):

```typescript title="lib/mailer.ts"

  host: 'smtp.emailit.com',
  port: 587,
  secure: false,
  requireTLS: true,
  auth: { user: 'emailit', pass: process.env.EMAILIT_API_KEY },
});
```

Depois, chame `await mailer.sendMail({ from, to, subject, html })`. As funções serverless abrem uma nova conexão SMTP na maioria das invocações, então a API costuma ser mais rápida na Vercel e em plataformas semelhantes. Consulte [Configurações de SMTP](/pt/docs/smtp/settings/).

## Receber webhooks

[Crie um webhook](/pt/docs/webhooks/set-up/) que aponte para `https://your-app.com/api/webhooks/emailit`. O handler precisa verificar a assinatura com base no corpo bruto, então leia-o com `request.text()` antes de interpretá-lo:

```typescript title="app/api/webhooks/emailit/route.ts"

type EmailitEvent = {
  event_id: string;
  type: string;
  data: { object: Record<string, unknown> };
};

function isValid(rawBody: string, signature: string | null, timestamp: string | null) {
  if (!signature || !timestamp) return false;
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
  if (!Number.isFinite(age) || age > 300) return false;
  const expected = createHmac('sha256', process.env.EMAILIT_WEBHOOK_SECRET!)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}

  const rawBody = await request.text();
  const valid = isValid(
    rawBody,
    request.headers.get('x-emailit-signature'),
    request.headers.get('x-emailit-timestamp'),
  );
  if (!valid) return new Response('Invalid signature', { status: 401 });

  // Each request carries an array of up to 100 events.
  const events = JSON.parse(rawBody) as EmailitEvent[];
  for (const event of events) {
    if (event.type === 'email.bounced') {
      // Flag event.data.object.to in your database.
    }
  }

  return new Response(null, { status: 200 });
}
```

Retorne um `2xx` em até 30 segundos; as outras respostas recebem novas tentativas. Consulte [Assinatura das requisições](/pt/docs/webhooks/request-signature/) e [Tipos de evento](/pt/docs/webhooks/event-types/).

## Dicas para produção

- **Mantenha os envios no servidor.** Apenas `lib/emailit.ts`, os route handlers e as server actions devem ter acesso à chave. `server-only` garante isso no momento do build.
- **Nunca deixe o cliente escolher o remetente.** Fixe `from` no código e só aceite `to` do navegador quando for o próprio endereço do usuário conectado.
- **Proteja os endpoints públicos.** Limite a taxa de requisições dos formulários de contato e das ações de cadastro e adicione um CAPTCHA se os bots os encontrarem. Cada e-mail custa créditos e conta para os seus [limites de envio](/pt/docs/limits/).
- **Defina variáveis por ambiente.** Use chaves separadas para os deploys de preview e de produção para poder revogar uma sem afetar a outra.

## Próximos passos

  - [Guia de Node.js](/pt/docs/frameworks/nodejs/): Tratamento de erros e Nodemailer em mais detalhes.
  - [Enviar e-mails com a API](/pt/docs/email-api/send-email/): Anexos, agendamento e rastreamento.
  - [Templates](/pt/docs/templates/): Crie os e-mails uma vez e envie-os pelo alias.
  - [Chaves de API](/pt/docs/developers/api-keys/): Escopos, restrições de domínio e rotação.

---
Fonte: https://emailit.com/pt/docs/frameworks/nextjs/
