Tutoriel
Envoyer des e-mails avec Node.js
Envoyez des e-mails depuis Node.js avec le SDK @emailit/node ou Nodemailer via SMTP, et vérifiez les webhooks Emailit dans une route Express.
Ce guide montre comment envoyer des e-mails depuis une application Node.js avec le SDK officiel @emailit/node, comment utiliser plutôt Nodemailer via SMTP, et comment recevoir des webhooks signés dans Express.
Prérequis
- Node.js 18 ou version ultérieure.
- Un domaine d’envoi vérifié, par exemple
acme.com. - Une clé API. Une clé Sending Only suffit pour envoyer.
- Tant que votre espace de travail n’a pas l’accès production, vous ne pouvez envoyer qu’aux adresses e-mail des comptes des membres de l’espace de travail. Utilisez votre propre adresse pendant vos tests.
Installer le SDK
npm install @emailit/nodeLe paquet est uniquement au format ESM. Utilisez la syntaxe import, ou await import('@emailit/node') depuis du code CommonJS.
Configurer votre clé API
Ne mettez pas la clé dans votre code. Placez-la dans une variable d’environnement :
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••Chargez le fichier avec node --env-file=.env (Node.js 20.6 et versions ultérieures), un paquet comme dotenv ou les paramètres de secrets de votre plateforme. Ajoutez .env à .gitignore.
Envoyer un e-mail
Créez un seul client et réutilisez-le d’une requête à l’autre :
import { Emailit } from '@emailit/node';
const emailit = new Emailit(process.env.EMAILIT_API_KEY);
const email = await emailit.emails.send({
from: 'Acme <hello@acme.com>',
to: 'ada@example.com',
subject: 'Welcome to Acme',
html: '<p>Thanks for signing up.</p>',
text: 'Thanks for signing up.',
});
console.log(email.id); // em_…Exécutez-le avec node --env-file=.env send.mjs. L’e-mail apparaît dans Email APIEmails en quelques secondes.
Dans une application Express, envoyez depuis la route qui déclenche l’e-mail :
import express from 'express';
import { Emailit } from '@emailit/node';
const app = express();
const emailit = new Emailit(process.env.EMAILIT_API_KEY);
app.post('/signup', express.json(), async (req, res) => {
const { email } = req.body;
// Create the user here, then send the welcome email.
const sent = await emailit.emails.send({
from: 'Acme <hello@acme.com>',
to: email,
template: 'welcome',
variables: { email },
});
res.status(201).json({ emailId: sent.id });
});
app.listen(3000);template accepte un alias de modèle ou un ID tem_, et variables le complète. Consultez Modèles et la liste complète des champs dans Envoyer un e-mail.
Gérer les erreurs
Le SDK lève des erreurs typées : vous pouvez donc réagir à chaque type d’échec :
import {
AuthenticationException,
RateLimitException,
UnprocessableEntityException,
ApiErrorException,
} from '@emailit/node';
try {
await emailit.emails.send(message);
} catch (err) {
if (err instanceof RateLimitException) {
// 429: wait err.jsonBody.retry_after seconds, then retry
} else if (err instanceof AuthenticationException) {
// 401: the API key is missing or invalid
} else if (err instanceof UnprocessableEntityException) {
// 422: for example, the from domain isn't verified
} else if (err instanceof ApiErrorException) {
console.error(err.httpStatus, err.jsonBody);
} else {
throw err;
}
}Envoyer plutôt via SMTP
Si votre application utilise déjà Nodemailer, faites-le pointer vers le relais SMTP Emailit. Installez-le avec npm install nodemailer :
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.emailit.com',
port: 587,
secure: false, // upgraded with STARTTLS after connecting
requireTLS: true,
auth: {
user: 'emailit',
pass: process.env.EMAILIT_API_KEY,
},
});
const info = await transporter.sendMail({
from: 'Acme <hello@acme.com>',
to: 'ada@example.com',
subject: 'Welcome to Acme',
text: 'Thanks for signing up.',
html: '<p>Thanks for signing up.</p>',
});
console.log(info.response); // 250 2.0.0 OK: queued as em_…Pour le port 465, définissez port: 465 et secure: true. Si votre réseau bloque le port 587, utilisez 2525 ou 2587 avec les mêmes paramètres. Consultez Paramètres SMTP.
Recevoir des webhooks
Créez un webhook qui pointe vers https://your-app.com/webhooks/emailit et copiez son secret de signature (whsec_…) dans EMAILIT_WEBHOOK_SECRET.
Emailit signe chaque requête avec un HMAC-SHA256 de timestamp.rawBody : la route doit donc lire le corps brut. Utilisez express.raw() sur cette route, pas express.json() :
import express from 'express';
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyEmailitSignature(rawBody, signature, timestamp, secret) {
if (!signature || !timestamp) return false;
const age = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return false; // reject replays older than 5 minutes
const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}
export const webhooks = express.Router();
webhooks.post('/webhooks/emailit', express.raw({ type: 'application/json' }), (req, res) => {
const rawBody = req.body.toString('utf8');
const valid = verifyEmailitSignature(
rawBody,
req.get('x-emailit-signature'),
req.get('x-emailit-timestamp'),
process.env.EMAILIT_WEBHOOK_SECRET,
);
if (!valid) return res.status(401).send('Invalid signature');
// The body is an array of up to 100 events.
const events = JSON.parse(rawBody);
for (const event of events) {
switch (event.type) {
case 'email.delivered':
// event.data.object.id is the em_ ID
break;
case 'email.bounced':
case 'email.complained':
// stop emailing event.data.object.to
break;
}
}
res.sendStatus(200);
});Montez le routeur avec app.use(webhooks) avant tout middleware global express.json(). Renvoyez un 2xx dans les 30 secondes ; pour toute autre réponse, Emailit réessaie. Pour plus de détails, consultez Signature des requêtes et Nouvelles tentatives et échecs.
Conseils pour la production
- Limitez la portée de la clé. Utilisez sur le serveur d’application une clé Sending Only limitée à votre domaine d’envoi. Réservez les clés Full Access aux scripts d’administration.
- Restez sous votre limite de débit. Par défaut, les nouveaux espaces de travail peuvent envoyer 2 e-mails par seconde et 5 000 par jour, partagés entre l’API et le SMTP. Envoyez les lots volumineux depuis une file d’attente. Avec Nodemailer,
pool: true, rateLimit: 2maintient un transport en pool à 2 messages par seconde. Consultez Limites. - Sécurisez les relances. Si vous relancez un envoi après un timeout, envoyez un en-tête
Idempotency-Keypour qu’Emailit n’envoie pas deux fois. Le SDK ne définit pas d’en-têtes personnalisés : utilisez doncfetchpour ces appels ; consultez Idempotence. - Traitez les webhooks de façon idempotente. Enregistrez chaque
event_idtraité et ignorez les doublons, et effectuez les traitements lents dans une tâche en arrière-plan après avoir renvoyé200. - Vous utilisez TypeScript ? Le SDK n’a pas encore de déclarations de types. Ajoutez
declare module '@emailit/node';à un fichier.d.tsde votre projet.