Tutoriál
Odesílání e-mailů z Node.js
Odesílejte e-maily z Node.js přes SDK @emailit/node, nebo přes SMTP s Nodemailerem, a ověřujte webhooky Emailitu v routě Expressu.
Tento návod ukazuje, jak odesílat e-maily z aplikace v Node.js přes oficiální SDK @emailit/node, jak místo toho použít Nodemailer přes SMTP a jak přijímat podepsané webhooky v Expressu.
Předpoklady
- Node.js 18 nebo novější.
- Ověřená odesílací doména, například
acme.com. - API klíč. K odesílání stačí klíč jen pro odesílání.
- Dokud váš workspace nemá produkční přístup, můžete odesílat jen na e-mailové adresy účtů členů workspace. Při testování používejte svou vlastní adresu.
Nainstalujte SDK
npm install @emailit/nodeBalíček je jen ve formátu ESM. Používejte syntaxi import, nebo v kódu CommonJS await import('@emailit/node').
Nastavte API klíč
Klíč nedávejte do kódu. Uložte ho do proměnné prostředí:
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••Soubor načtěte pomocí node --env-file=.env (Node.js 20.6 a novější), balíčku jako dotenv, nebo nastavení tajných údajů vaší platformy. Soubor .env přidejte do .gitignore.
Odešlete e-mail
Vytvořte jednoho klienta a používejte ho pro všechny požadavky:
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_…Spusťte ho příkazem node --env-file=.env send.mjs. E-mail se během několika sekund objeví v Email APIEmails.
V aplikaci v Expressu odesílejte z routy, která e-mail spouští:
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 přijímá alias šablony nebo ID tem_ a variables šablonu vyplní. Viz Šablony a úplný seznam polí na stránce Odeslání e-mailu.
Ošetřete chyby
SDK vyhazuje typované chyby, takže můžete na každé selhání reagovat zvlášť:
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;
}
}Odesílání přes SMTP
Pokud vaše aplikace už používá Nodemailer, nasměrujte ho na SMTP relay Emailitu. Nainstalujte ho příkazem 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_…Pro port 465 nastavte port: 465 a secure: true. Pokud vaše síť blokuje port 587, použijte se stejným nastavením port 2525 nebo 2587. Viz Nastavení SMTP.
Přijímejte webhooky
Vytvořte webhook, který míří na https://your-app.com/webhooks/emailit, a jeho tajný klíč (whsec_…) zkopírujte do EMAILIT_WEBHOOK_SECRET.
Emailit podepisuje každý požadavek pomocí HMAC-SHA256 z timestamp.rawBody, takže routa musí číst surové tělo požadavku. Na této routě použijte express.raw(), ne 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);
});Router připojte pomocí app.use(webhooks) dřív než jakýkoli globální middleware express.json(). Do 30 sekund vraťte 2xx; cokoli jiného se opakuje. Podrobnosti najdete na stránkách Ověření podpisu webhooků a Opakování a selhání.
Tipy pro produkční provoz
- Omezte oprávnění klíče. Pro aplikační server použijte klíč jen pro odesílání omezený na vaši odesílací doménu. Klíče s plným přístupem si nechte pro administrativní skripty.
- Držte se pod limitem rychlosti. Nové workspace mohou ve výchozím stavu odeslat 2 e-maily za sekundu a 5 000 za den, společně přes API i SMTP. Hromadné úlohy odesílejte z fronty. U Nodemaileru udrží
pool: true, rateLimit: 2transport s poolem spojení na 2 zprávách za sekundu. Viz Limity a kvóty. - Zajistěte bezpečné opakování. Pokud po vypršení časového limitu odeslání opakujete, pošlete hlavičku
Idempotency-Key, aby Emailit neodeslal e-mail dvakrát. SDK vlastní hlavičky nenastavuje, proto pro tato volání použijtefetch; viz Idempotentní požadavky. - Zpracovávejte webhooky idempotentně. Ukládejte si každé zpracované
event_id, duplicity přeskakujte a pomalou práci dělejte v úloze na pozadí až poté, co vrátíte200. - Používáte TypeScript? SDK zatím nemá deklarace typů. Přidejte do svého projektu soubor
.d.tssdeclare module '@emailit/node';.