# Enviar emails con Node.js

> Envía emails desde Node.js con el SDK @emailit/node o con Nodemailer por SMTP, y verifica los webhooks de Emailit en una ruta de Express.

En esta guía se explica cómo enviar emails desde una aplicación Node.js con el SDK oficial `@emailit/node`, cómo usar en su lugar Nodemailer por SMTP y cómo recibir webhooks firmados en Express.

## Requisitos previos

- Node.js 18 o posterior.
- Un [dominio de envío verificado](/es/docs/domains/add-a-domain/), por ejemplo `acme.com`.
- Una [clave de API](/es/docs/developers/api-keys/). Para enviar basta con una clave Sending Only.
- Hasta que tu espacio de trabajo tenga [acceso de producción](/es/docs/workspaces/production-access/), solo puedes enviar a las direcciones de email de las cuentas de los miembros del espacio de trabajo. Usa tu propia dirección mientras haces pruebas.

## Instalar el SDK

```bash
npm install @emailit/node
```

El paquete es solo ESM. Usa la sintaxis `import`, o `await import('@emailit/node')` desde código CommonJS.

## Configurar la clave de API

No pongas la clave en tu código. Guárdala en una variable de entorno:

```bash title=".env"
EMAILIT_API_KEY=secret_••••••••••••••••••••••••••••••••
```

Carga el archivo con `node --env-file=.env` (Node.js 20.6 y posterior), con un paquete como `dotenv` o con la configuración de secretos de tu plataforma. Añade `.env` a `.gitignore`.

## Enviar un email

Crea un único cliente y reutilízalo en todas las peticiones:

```javascript title="send.mjs"

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_…
```

Ejecútalo con `node --env-file=.env send.mjs`. El email aparece en **Email API → Emails** en unos segundos.

En una aplicación Express, envía desde la ruta que desencadena el email:

```javascript title="server.mjs"

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` acepta el alias o el ID `tem_` de una plantilla, y `variables` la rellena. Consulta [Plantillas](/es/docs/templates/) y la lista completa de campos en [Enviar un email](/es/docs/api-reference/emails/send/).

## Gestionar los errores

El SDK lanza errores tipados, así que puedes reaccionar a cada fallo:

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

## Enviar por SMTP

Si tu aplicación ya usa [Nodemailer](https://nodemailer.com), apúntalo al SMTP relay de Emailit. Instálalo con `npm install nodemailer`:

```javascript title="mailer.mjs"

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_…
```

Para el puerto 465, define `port: 465` y `secure: true`. Si tu red bloquea el 587, usa el 2525 o el 2587 con la misma configuración. Consulta [Configuración SMTP](/es/docs/smtp/settings/).

## Recibir webhooks

[Crea un webhook](/es/docs/webhooks/set-up/) que apunte a `https://your-app.com/webhooks/emailit` y copia su secreto de firma (`whsec_…`) en `EMAILIT_WEBHOOK_SECRET`.

Emailit firma cada petición con un HMAC-SHA256 de `timestamp.rawBody`, así que la ruta debe leer el cuerpo en bruto. Usa `express.raw()` en esta ruta, no `express.json()`:

```javascript title="webhooks.mjs"

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

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 el router con `app.use(webhooks)` antes de cualquier middleware global `express.json()`. Devuelve un `2xx` en menos de 30 segundos; cualquier otra respuesta se reintenta. Para más detalles, lee [Firma de las peticiones](/es/docs/webhooks/request-signature/) y [Reintentos y fallos](/es/docs/webhooks/retries-and-failures/).

## Consejos para producción

- **Limita el permiso de la clave.** Usa en el servidor de la aplicación una clave Sending Only limitada a tu dominio de envío. Reserva las claves Full Access para los scripts de administración.
- **No superes tu límite de velocidad.** Por defecto, los espacios de trabajo nuevos pueden enviar 2 emails por segundo y 5000 al día, compartidos entre la API y SMTP. Haz los envíos masivos desde una cola. Con Nodemailer, `pool: true, rateLimit: 2` mantiene un transporte con pool a 2 mensajes por segundo. Consulta [Límites y cuotas](/es/docs/limits/).
- **Haz que los reintentos sean seguros.** Si reintentas un envío después de que se agote el tiempo de espera, envía una cabecera `Idempotency-Key` para que Emailit no lo envíe dos veces. El SDK no permite cabeceras personalizadas, así que usa `fetch` para esas llamadas; consulta [Idempotencia](/es/docs/email-api/idempotency/).
- **Procesa los webhooks de forma idempotente.** Guarda cada `event_id` que hayas procesado y omite los duplicados, y haz el trabajo lento en una tarea en segundo plano después de devolver `200`.
- **¿Usas TypeScript?** El SDK aún no tiene declaraciones de tipos. Añade `declare module '@emailit/node';` a un archivo `.d.ts` de tu proyecto.

## Próximos pasos

  - [Enviar emails con la API](/es/docs/email-api/send-email/): Adjuntos, programación, seguimiento y metadatos.
  - [Tipos de eventos de webhook](/es/docs/webhooks/event-types/): Todos los eventos y su payload.
  - [Next.js](/es/docs/frameworks/nextjs/): Route handlers y server actions.
  - [SDK y bibliotecas](/es/docs/sdks/): Todas las bibliotecas oficiales.

---
Fuente: https://emailit.com/es/docs/frameworks/nodejs/
