Tutorial 7 min de lectura Actualizado abril de 2026

Cómo enviar emails transaccionales con Node.js (con ejemplos de código)

Dos enfoques: la API REST de Emitlo (recomendada para nuevos proyectos) y Nodemailer + SMTP (para codebases existentes). Ambos usan Emitlo como infraestructura de envío.

Estos ejemplos usan la API de Emitlo. Regístrate gratis para seguir — 12.000 emails/mes, sin tarjeta de crédito.

Método 1: API REST de Emitlo (fetch)

El enfoque más simple — sin dependencias requeridas. Funciona en Node.js 18+ con la API fetch nativa.

// enviar-email.js
const response = await fetch('https://api.emitlo.com/v1/messages', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.EMITLO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Bienvenido a nuestra app',
    html: '<h1>¡Bienvenido!</h1><p>Gracias por registrarte.</p>',
    text: '¡Bienvenido! Gracias por registrarte.',
  }),
});

if (!response.ok) {
  const error = await response.json();
  throw new Error(`Email fallido: ${error.message}`);
}

const result = await response.json();
console.log('Enviado:', result.id); // msg_8f2c...

Método 2: API REST de Emitlo (axios)

// npm install axios
const axios = require('axios');

async function enviarEmail({ to, subject, html, text }) {
  const { data } = await axios.post(
    'https://api.emitlo.com/v1/messages',
    { from: '[email protected]', to, subject, html, text },
    {
      headers: {
        Authorization: `Bearer ${process.env.EMITLO_API_KEY}`,
      },
    }
  );
  return data; // { id: 'msg_8f2c...', status: 'queued' }
}

// Uso
await enviarEmail({
  to: '[email protected]',
  subject: 'Tu pedido está confirmado',
  html: '<h1>Pedido #1234 confirmado</h1>',
  text: 'Pedido #1234 confirmado',
});
Estos ejemplos usan la API de Emitlo. Regístrate gratis para seguir →

Método 3: Nodemailer + SMTP

Usa este enfoque si tienes un codebase existente que usa Nodemailer. Solo actualiza las credenciales SMTP para usar Emitlo.

// npm install nodemailer
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  host: 'smtp.emitlo.com',
  port: 587,
  secure: false, // usar STARTTLS
  auth: {
    user: process.env.EMITLO_SMTP_USER,
    pass: process.env.EMITLO_SMTP_PASS,
  },
});

async function enviarEmail({ to, subject, html, text }) {
  const info = await transporter.sendMail({
    from: '"Tu App" <[email protected]>',
    to,
    subject,
    html,
    text,
  });
  return info.messageId;
}

// Uso
await enviarEmail({
  to: '[email protected]',
  subject: 'Restablecimiento de contraseña',
  html: '<p>Haz clic <a href="...">aquí</a> para restablecer tu contraseña.</p>',
  text: 'Visita este enlace para restablecer tu contraseña: ...',
});

Enviar email HTML

Siempre incluye versiones HTML y de texto plano. Algunos clientes de email muestran texto plano por defecto, y los filtros de spam buscan la presencia de una versión de texto plano.

const emailHtml = `
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
  <h1 style="color: #1a1a2e;">Bienvenido a Nuestra App</h1>
  <p>Hola ${usuario.nombre},</p>
  <p>Gracias por registrarte. Haz clic en el botón de abajo para verificar tu email.</p>
  <a href="${urlVerificacion}" 
     style="display: inline-block; background: #6c3ff9; color: white; 
            padding: 12px 24px; border-radius: 8px; text-decoration: none;">
    Verificar Email
  </a>
</body>
</html>
`;

const emailTexto = `
Bienvenido a Nuestra App

Hola ${usuario.nombre},

Gracias por registrarte. Visita este enlace para verificar tu email:
${urlVerificacion}
`;

Enviar con adjuntos

// API REST con adjunto
const fs = require('fs');
const pdfBuffer = fs.readFileSync('./factura.pdf');

await fetch('https://api.emitlo.com/v1/messages', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.EMITLO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Tu factura #FAC-1234',
    html: '<p>Por favor encuentra tu factura adjunta.</p>',
    text: 'Por favor encuentra tu factura adjunta.',
    attachments: [{
      filename: 'factura-1234.pdf',
      content: pdfBuffer.toString('base64'),
      contentType: 'application/pdf',
    }],
  }),
});

Manejo de errores

async function enviarEmailSeguro({ to, subject, html, text }) {
  try {
    const response = await fetch('https://api.emitlo.com/v1/messages', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.EMITLO_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ from: '[email protected]', to, subject, html, text }),
    });

    if (response.status === 429) {
      // Límite de velocidad — reintentar después de retraso
      const retryAfter = response.headers.get('Retry-After') || 60;
      throw new Error(`Límite de velocidad. Reintentar después de ${retryAfter}s`);
    }

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Error API email ${response.status}: ${error.message}`);
    }

    return await response.json();
  } catch (err) {
    // Registrar error con contexto para depuración
    console.error('Fallo al enviar email', { to, subject, error: err.message });
    throw err; // Relanzar para que el llamador gestione
  }
}

Variables de entorno

Nunca codifiques las claves API directamente. Usa variables de entorno:

# .env
EMITLO_API_KEY=tu_clave_api_aqui
EMITLO_SMTP_USER=tu_usuario_smtp
EMITLO_SMTP_PASS=tu_contraseña_smtp
[email protected]
// Cargar con dotenv
require('dotenv').config();
const apiKey = process.env.EMITLO_API_KEY;

Empieza a enviar emails transaccionales en Node.js — gratis

12.000 emails/mes (400/día) · API REST + SMTP · Sin tarjeta de crédito

Preguntas frecuentes

¿Cuál es la mejor forma de enviar email transaccional en Node.js?
Para nuevos proyectos, usa una API REST (como la de Emitlo) con la API fetch nativa o axios. Para proyectos existentes que usan Nodemailer, configúralo con las credenciales SMTP de Emitlo. El enfoque de API REST ofrece mejor manejo de errores y respuestas estructuradas.
¿Debería usar Nodemailer o una API REST para email transaccional?
Ambos funcionan bien. Nodemailer + SMTP es más fácil de integrar en codebases existentes. La API REST ofrece mejor manejo de errores, respuestas estructuradas y es preferida para nuevas aplicaciones. Emitlo soporta ambos con las mismas credenciales y límites de velocidad.
¿Cómo gestiono errores de email en Node.js?
Siempre envuelve el envío de emails en try/catch. Verifica el código de estado HTTP para llamadas a la API REST (200 = éxito, 4xx = error del cliente, 5xx = error del servidor). Para SMTP, Nodemailer lanza errores para fallos de conexión y mensajes rechazados. Registra los errores con suficiente contexto para depurar (destinatario, asunto, mensaje de error).
¿Cómo envío email HTML en Node.js?
Pasa tu cadena HTML como propiedad html en el cuerpo de la solicitud (API REST) o la opción html en Nodemailer. Siempre incluye una alternativa de texto plano (propiedad text) para clientes de email que no renderizan HTML.
¿Cómo envío email con adjuntos en Node.js?
Con la API REST de Emitlo, incluye un array attachments en el cuerpo de la solicitud con el contenido del archivo codificado en base64. Con Nodemailer, usa la opción attachments con path, content o buffer. El plan gratuito de Emitlo soporta adjuntos de hasta 10 MB.

Guías relacionadas: