Vai al contenuto
Docs

Tutorial

Invia email da Node.js con l’SDK @emailit/node o con Nodemailer via SMTP, e verifica i webhook di Emailit in una route Express.

Aggiornato il 1 ott 2026

Questa guida mostra come inviare email da un’app Node.js con l’SDK ufficiale @emailit/node, come usare in alternativa Nodemailer via SMTP e come ricevere webhook firmati in Express.

Prerequisiti

  • Node.js 18 o versioni successive.
  • Un dominio di invio verificato, ad esempio acme.com.
  • Una chiave API. Per inviare basta una chiave di solo invio.
  • Finché il workspace non ha l’accesso alla produzione, puoi inviare solo agli indirizzi email degli account dei membri del workspace. Durante i test usa il tuo indirizzo.

Installa l’SDK

Terminal
npm install @emailit/node

Il pacchetto è solo ESM. Usa la sintassi import, oppure await import('@emailit/node') dal codice CommonJS.

Configura la chiave API

Tieni la chiave fuori dal codice. Mettila in una variabile d’ambiente:

.env
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••

Carica il file con node --env-file=.env (Node.js 20.6 e versioni successive), con un pacchetto come dotenv o con le impostazioni dei secret della tua piattaforma. Aggiungi .env a .gitignore.

Invia un’email

Crea un unico client e riutilizzalo tra le richieste:

send.mjs
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_…

Eseguilo con node --env-file=.env send.mjs. L’email compare in Email APIEmails in pochi secondi.

In un’app Express, invia dalla route che genera l’email:

server.mjs
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 accetta l’alias di un template o un ID tem_, e variables lo compila. Vedi Template e l’elenco completo dei campi in Invia un’email.

Gestisci gli errori

L’SDK lancia errori tipizzati, così puoi reagire a ogni tipo di errore:

JavaScript
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;
  }
}

Invia con SMTP

Se la tua app usa già Nodemailer, indirizzalo all’SMTP relay di Emailit. Installalo con npm install nodemailer:

mailer.mjs
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_…

Per la porta 465, imposta port: 465 e secure: true. Se la tua rete blocca la 587, usa la 2525 o la 2587 con le stesse impostazioni. Vedi Impostazioni SMTP.

Ricevi i webhook

Crea un webhook che punta a https://your-app.com/webhooks/emailit e copia il suo secret di firma (whsec_…) in EMAILIT_WEBHOOK_SECRET.

Emailit firma ogni richiesta con un HMAC-SHA256 di timestamp.rawBody, quindi la route deve leggere il corpo grezzo. Su questa route usa express.raw(), non express.json():

webhooks.mjs
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);
});

Monta il router con app.use(webhooks) prima di qualsiasi middleware globale express.json(). Restituisci un 2xx entro 30 secondi; qualsiasi altra risposta viene ritentata. Per i dettagli, leggi Firma delle richieste e Nuovi tentativi ed errori.

Consigli per la produzione

  • Limita il permesso della chiave. Per il server dell’app usa una chiave di solo invio limitata al tuo dominio di invio. Riserva le chiavi con accesso completo agli script di amministrazione.
  • Resta entro il limite di frequenza. Per impostazione predefinita, i nuovi workspace possono inviare 2 email al secondo e 5000 al giorno, condivise tra API e SMTP. Esegui gli invii massivi da una coda. Con Nodemailer, pool: true, rateLimit: 2 mantiene un transport in pool a 2 messaggi al secondo. Vedi Limiti e quote.
  • Rendi sicuri i nuovi tentativi. Se ritenti un invio dopo un timeout, invia un header Idempotency-Key così Emailit non invia due volte. L’SDK non imposta header personalizzati, quindi per queste chiamate usa fetch; vedi Idempotenza.
  • Elabora i webhook in modo idempotente. Salva ogni event_id che hai gestito e salta i duplicati, ed esegui il lavoro lento in un job in background dopo aver restituito 200.
  • Usi TypeScript? L’SDK non ha ancora dichiarazioni di tipo. Aggiungi declare module '@emailit/node'; a un file .d.ts nel tuo progetto.

Passaggi successivi

Allegati, programmazione, tracciamento e metadati.
Ogni evento e il suo payload.
Route handler e server action.
Tutte le librerie ufficiali.

Questa pagina ti è stata utile?

Grazie del feedback.

Grazie, leggiamo ogni messaggio.