Tutorial
E-Mails mit Node.js senden
Senden Sie E-Mails aus Node.js mit dem SDK @emailit/node oder per SMTP mit Nodemailer und verifizieren Sie Emailit-Webhooks in einer Express-Route.
Diese Anleitung zeigt, wie Sie E-Mails aus einer Node.js-App mit dem offiziellen SDK @emailit/node senden, wie Sie stattdessen Nodemailer per SMTP verwenden und wie Sie signierte Webhooks in Express empfangen.
Voraussetzungen
- Node.js 18 oder neuer.
- Eine verifizierte Versanddomain, zum Beispiel
acme.com. - Ein API-Schlüssel. Zum Senden genügt ein reiner Sende-Schlüssel.
- Solange Ihr Workspace keinen Produktionszugang hat, können Sie nur an die Konto-E-Mail-Adressen von Workspace-Mitgliedern senden. Verwenden Sie zum Testen Ihre eigene Adresse.
SDK installieren
npm install @emailit/nodeDas Paket unterstützt nur ESM. Verwenden Sie die import-Syntax oder in CommonJS-Code await import('@emailit/node').
API-Schlüssel konfigurieren
Halten Sie den Schlüssel aus Ihrem Code heraus. Legen Sie ihn in einer Umgebungsvariablen ab:
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••Laden Sie die Datei mit node --env-file=.env (ab Node.js 20.6), einem Paket wie dotenv oder über die Secret-Einstellungen Ihrer Plattform. Nehmen Sie .env in .gitignore auf.
E-Mail senden
Erstellen Sie einen Client und verwenden Sie ihn für alle Anfragen wieder:
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_…Führen Sie es mit node --env-file=.env send.mjs aus. Die E-Mail erscheint innerhalb von Sekunden unter Email APIEmails.
In einer Express-App senden Sie aus der Route, die die E-Mail auslöst:
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 akzeptiert einen Vorlagen-Alias oder eine tem_-ID, und variables füllt die Vorlage. Siehe Vorlagen und die vollständige Liste der Felder unter E-Mail senden.
Fehler behandeln
Das SDK wirft typisierte Fehler, sodass Sie auf jeden Fehlerfall gezielt reagieren können:
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;
}
}Alternativ per SMTP senden
Wenn Ihre App bereits Nodemailer verwendet, richten Sie es auf das SMTP-Relay von Emailit aus. Installieren Sie es mit 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_…Für Port 465 setzen Sie port: 465 und secure: true. Wenn Ihr Netzwerk 587 blockiert, verwenden Sie 2525 oder 2587 mit denselben Einstellungen. Siehe SMTP-Einstellungen.
Webhooks empfangen
Erstellen Sie einen Webhook, der auf https://your-app.com/webhooks/emailit zeigt, und kopieren Sie sein Signatur-Secret (whsec_…) in EMAILIT_WEBHOOK_SECRET.
Emailit signiert jede Anfrage mit einem HMAC-SHA256 von timestamp.rawBody; die Route muss daher den unveränderten Body lesen. Verwenden Sie auf dieser Route express.raw(), nicht 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);
});Binden Sie den Router mit app.use(webhooks) vor jeder globalen express.json()-Middleware ein. Geben Sie innerhalb von 30 Sekunden einen 2xx-Status zurück; alles andere wird wiederholt. Details finden Sie unter Anfragesignatur und Wiederholungen und Fehlschläge.
Tipps für den Produktivbetrieb
- Scope des Schlüssels einschränken. Verwenden Sie für den App-Server einen reinen Sende-Schlüssel, der auf Ihre Versanddomain beschränkt ist. Behalten Sie Schlüssel mit Vollzugriff für Admin-Skripte vor.
- Unter dem Rate Limit bleiben. Neue Workspaces können standardmäßig 2 E-Mails pro Sekunde und 5.000 pro Tag senden, gemeinsam für API und SMTP. Senden Sie Massen-Jobs aus einer Warteschlange. Mit Nodemailer hält
pool: true, rateLimit: 2einen gepoolten Transport bei 2 Nachrichten pro Sekunde. Siehe Limits. - Wiederholungen sicher machen. Wenn Sie einen Versand nach einem Timeout wiederholen, senden Sie einen Header
Idempotency-Key, damit Emailit nicht doppelt sendet. Das SDK setzt keine eigenen Header, verwenden Sie für diese Aufrufe daherfetch. Siehe Idempotenz. - Webhooks idempotent verarbeiten. Speichern Sie jede verarbeitete
event_idund überspringen Sie Duplikate. Erledigen Sie langsame Arbeit in einem Hintergrundjob, nachdem Sie200zurückgegeben haben. - TypeScript im Einsatz? Das SDK hat noch keine Typdeklarationen. Fügen Sie
declare module '@emailit/node';in eine.d.ts-Datei in Ihrem Projekt ein.