# Envoyer des e-mails avec Next.js

> Envoyez des e-mails depuis les route handlers et les server actions de Next.js avec le SDK Node.js d’Emailit, gardez la clé API côté serveur et vérifiez les webhooks.

Ce guide montre comment envoyer des e-mails depuis une application Next.js avec le SDK `@emailit/node`, à la fois depuis un route handler et depuis une server action, et comment vérifier les webhooks Emailit. Les exemples utilisent l’App Router ; le Pages Router est traité à la fin de la partie consacrée à l’envoi.

## Prérequis

- Next.js 14 ou version ultérieure. Le SDK nécessite Node.js 18 ou version ultérieure.
- Un [domaine d’envoi vérifié](/fr/docs/domains/add-a-domain/), par exemple `acme.com`.
- Une [clé API](/fr/docs/developers/api-keys/). Une clé Sending Only limitée à votre domaine suffit.
- Tant que votre espace de travail n’a pas l’[accès production](/fr/docs/workspaces/production-access/), vous ne pouvez envoyer qu’aux adresses e-mail des comptes des membres de l’espace de travail.

## Installer le SDK

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

`server-only` fait échouer le build si un composant client importe le module qui contient votre clé.

## Configurer votre clé API

Ajoutez la clé dans `.env.local` pour le développement, et dans les variables d’environnement de votre hébergeur (par exemple les paramètres du projet Vercel) pour la production :

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

> **N’exposez jamais la clé au navigateur:** Ne préfixez pas ces variables par `NEXT_PUBLIC_`, et n’appelez pas Emailit depuis des composants client. Tout ce qui est préfixé par `NEXT_PUBLIC_` est intégré au JavaScript que chaque visiteur peut lire.

Créez un seul client dans un module réservé au serveur :

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

```

Le SDK n’a pas encore de déclarations TypeScript. Si le compilateur signale une erreur, ajoutez un fichier de déclaration :

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

## Envoyer depuis un route handler

Un route handler est l’endroit idéal pour les envois déclenchés par votre propre frontend ou par d’autres services. Ce handler de formulaire de contact envoie à une adresse interne fixe : les visiteurs ne peuvent donc pas l’utiliser pour envoyer des e-mails à n’importe qui :

```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 });
  }
}
```

Appelez-le depuis le navigateur avec `fetch('/api/contact', { method: 'POST', body: JSON.stringify(data) })`. La clé ne quitte jamais le serveur.

## Envoyer depuis une server action

Les server actions s’exécutent sur le serveur : elles peuvent donc utiliser le client directement :

```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` accepte un alias de modèle ou un ID `tem_` ; consultez [Modèles](/fr/docs/templates/). Les server actions sont des endpoints publics : validez donc les entrées et ajoutez vos protections habituelles contre les robots et les abus avant d’envoyer.

### Pages Router

Avec le Pages Router, envoyez plutôt depuis une route d’API :

```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 });
}
```

## Envoyer plutôt via SMTP

Si vous utilisez déjà Nodemailer, configurez-le avec le relais Emailit dans un route handler ou une server action (le SMTP nécessite le runtime Node.js, pas le 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 },
});
```

Appelez ensuite `await mailer.sendMail({ from, to, subject, html })`. Les fonctions serverless ouvrent une nouvelle connexion SMTP à la plupart des invocations : l’API est donc généralement plus rapide sur Vercel et les plateformes similaires. Consultez [Paramètres SMTP](/fr/docs/smtp/settings/).

## Recevoir des webhooks

[Créez un webhook](/fr/docs/webhooks/set-up/) qui pointe vers `https://your-app.com/api/webhooks/emailit`. Le handler doit vérifier la signature à partir du corps brut : lisez-le donc avec `request.text()` avant de l’analyser :

```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 });
}
```

Renvoyez un `2xx` dans les 30 secondes ; pour toute autre réponse, Emailit réessaie. Consultez [Signature des requêtes](/fr/docs/webhooks/request-signature/) et [Types d’événements](/fr/docs/webhooks/event-types/).

## Conseils pour la production

- **Gardez les envois côté serveur.** Seuls `lib/emailit.ts`, les route handlers et les server actions doivent accéder à la clé. `server-only` l’impose au moment du build.
- **Ne laissez jamais le client choisir l’expéditeur.** Codez `from` en dur, et n’acceptez `to` depuis le navigateur que s’il s’agit de l’adresse de l’utilisateur connecté.
- **Protégez les endpoints publics.** Limitez le débit des formulaires de contact et des actions d’inscription, et ajoutez un CAPTCHA si des robots les trouvent. Chaque e-mail coûte des crédits et compte dans vos [limites d’envoi](/fr/docs/limits/).
- **Définissez les variables par environnement.** Utilisez des clés distinctes pour les déploiements de prévisualisation et de production, afin de pouvoir révoquer l’une sans affecter l’autre.

## Étapes suivantes

  - [Guide Node.js](/fr/docs/frameworks/nodejs/): La gestion des erreurs et Nodemailer plus en détail.
  - [Envoyer des e-mails avec l’API](/fr/docs/email-api/send-email/): Pièces jointes, programmation et suivi.
  - [Modèles](/fr/docs/templates/): Concevez vos e-mails une fois, envoyez-les par alias.
  - [Clés API](/fr/docs/developers/api-keys/): Portées, limitation à un domaine et rotation.

---
Source: https://emailit.com/fr/docs/frameworks/nextjs/
