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