Email

Enviar correos electrónicos con Nodemailer

Nodemailer es la biblioteca estándar para enviar correo electrónico desde un servidor Node.js. Creas un transporte apuntando a un servidor SMTP y luego llamas a sendMail con los campos del mensaje. Se encarga del pool de conexiones, los archivos adjuntos y los cuerpos HTML. El código a continuación es lo mínimo que necesitas para enviar un mensaje real, más el truco de pruebas que la mayoría pasa por alto.

¿Cómo instalas y configuras Nodemailer?

Instálalo desde npm:

npm install nodemailer

Un transporte guarda los datos de conexión SMTP. Lo apuntas a un host y un puerto, y luego pasas las credenciales en auth:

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.example.com",
  port: 587,
  secure: false, // true for port 465, false for 587 (STARTTLS)
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

El puerto 587 con secure: false usa STARTTLS, que eleva la conexión a TLS después del handshake. El puerto 465 requiere secure: true. Guarda el usuario y la contraseña en variables de entorno, nunca en el código fuente.

¿Cómo envías un mensaje?

Llama a sendMail con el sobre y el contenido. Devuelve una promesa, así que envuélvelo en async/await con un try/catch para que un envío fallido no haga caer el proceso:

async function main() {
  try {
    const info = await transporter.sendMail({
      from: '"Your App" <you@yourdomain.com>',
      to: "recipient@example.org",
      subject: "Your receipt",
      text: "Thanks for your order. This is the plain-text version.",
      html: "<p>Thanks for your order.</p>",
    });
    console.log("Sent:", info.messageId);
  } catch (err) {
    console.error("Send failed:", err);
  }
}

main();

Envía siempre tanto text como html. Algunos clientes muestran la parte de texto plano, y un mensaje sin alternativa de texto tiende a puntuar peor en los filtros de spam.

¿Cómo añades archivos adjuntos?

Pasa un arreglo attachments. Cada entrada puede leer desde una ruta, un buffer o un stream:

await transporter.sendMail({
  from: "you@yourdomain.com",
  to: "recipient@example.org",
  subject: "Your invoice",
  text: "Invoice attached.",
  attachments: [
    {
      filename: "invoice.pdf",
      path: "./invoices/invoice-1042.pdf",
    },
    {
      filename: "note.txt",
      content: "Generated at runtime, no file needed.",
    },
  ],
});

¿Cómo pruebas sin enviar correo real?

Nodemailer incluye Ethereal, un servicio SMTP falso que captura los mensajes en lugar de entregarlos. Obtienes una URL de vista previa por cada envío, ideal para desarrollo local:

const testAccount = await nodemailer.createTestAccount();

const transporter = nodemailer.createTransport({
  host: "smtp.ethereal.email",
  port: 587,
  secure: false,
  auth: {
    user: testAccount.user,
    pass: testAccount.pass,
  },
});

const info = await transporter.sendMail({
  from: "you@yourdomain.com",
  to: "test@example.org",
  subject: "Preview only",
  text: "This never leaves Ethereal.",
});

console.log("Preview:", nodemailer.getTestMessageUrl(info));

Ethereal sirve para inspeccionar lo que construiste. No te dice nada sobre si una bandeja de entrada real aceptaría el mensaje.

Envíalo con Bird

SMTP funciona, pero usarlo en producción implica operar un servidor de correo (o alquilar uno), calentar IPs y vigilar la reputación tú mismo. Una HTTP API se encarga de todo eso. No hay un socket SMTP que mantener abierto, y el proveedor gestiona la infraestructura de entregabilidad. Con la Bird de correo electrónico API el mismo envío es una sola llamada:

import { BirdClient } from "@messagebird/sdk";

const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });

const { data, error } = await bird.email
  .send({
    from: "you@yourdomain.com",
    to: ["delivered@bird.dev"],
    subject: "Hello from Node",
    html: "<p>It works.</p>",
  })
  .safe();

La dirección sandbox delivered@bird.dev siempre acepta correo, así que puedes confirmar la integración antes de apuntar a un destinatario real. Las plataformas serverless son el caso más claro para este enfoque, ya que sus tiempos de ejecución de funciones a menudo no pueden mantener conexiones SMTP abiertas. Consulta cómo enviar correo en Vercel para esa ruta, y la guía general de enviar correo con JavaScript para saber dónde encaja el código de correo en tu stack.

Preguntas frecuentes

¿Funciona Nodemailer en el navegador?

No. Nodemailer es una biblioteca del lado del servidor y depende de los módulos de red de Node. Los navegadores no pueden abrir conexiones SMTP, y poner credenciales en código del cliente las expondría. Envía desde un backend en su lugar.

¿Por qué enviar tanto texto como HTML?

Un mensaje multipart permite que cada cliente elija la parte que puede renderizar, y la alternativa en texto plano mejora cómo los filtros de spam interpretan el mensaje. Omitir text es una razón común por la que los correos terminan en spam.

¿Debería usar SMTP o una HTTP API?

SMTP está bien para volúmenes bajos y herramientas internas. Para envíos en producción a escala, una HTTP API elimina el servidor que de otro modo tendrías que operar e incorpora el manejo de entregabilidad. Muchos equipos usan Nodemailer en desarrollo y una API en producción.

Nodemailer es una opción sólida para hablar SMTP desde Node. Cuando prefieras no operar el servidor de correo detrás de él, lee la guía de envío de correo para ver la alternativa API de principio a fin.

Construye sobre la misma red.

Obtén una clave API de prueba de inmediato. El acceso a producción se desbloquea cuando añades un método de pago y verificas un remitente.

Tu próxima idea.
Lista para conectar.