Saltar al contenido principal

Enviar Emails con Node.js en 2026: Nodemailer + Resend (Guía Completa)

Tutorial actualizado para enviar emails con Node.js usando Nodemailer con SMTP y Resend con su SDK. Includes HTML templates, adjuntos y gestión de errores.

Fran Cobos 4 min de lectura 651 palabras

Tabla de contenidos

Enviar emails con Node.js parece sencillo hasta que tus mensajes acaban en spam, el token de Gmail expira a las 24h o el SDK de turno tiene breaking changes sin documentar. Esta guía cubre las dos opciones que funcionan en 2026.

Opción 1: Resend (la opción moderna)

Resend es el servicio diseñado para developers. Tier gratuito generoso, SDK limpio y soporte para React Email.

Instalar

npm install resend

Envío básico

import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

async function enviarBienvenida(email: string, nombre: string) {
  const { data, error } = await resend.emails.send({
    from: 'Fran <hola@tudominio.com>',
    to: email,
    subject: `Bienvenido, ${nombre}`,
    html: `
      <h1>Hola ${nombre} 👋</h1>
      <p>Gracias por registrarte. Ya puedes acceder a tu cuenta.</p>
      <a href="https://tuapp.com/dashboard">Ir al dashboard</a>
    `,
  });

  if (error) {
    console.error('Error enviando email:', error);
    throw new Error(error.message);
  }

  return data;
}

Con React Email (templates reutilizables)

npm install @react-email/components
// emails/bienvenida.tsx
import { Html, Head, Body, Container, Heading, Text, Button } from '@react-email/components';

interface BienvenidaEmailProps {
  nombre: string;
  loginUrl: string;
}

export default function BienvenidaEmail({ nombre, loginUrl }: BienvenidaEmailProps) {
  return (
    <Html>
      <Head />
      <Body style={{ fontFamily: 'sans-serif', backgroundColor: '#f4f4f4' }}>
        <Container style={{ maxWidth: '560px', margin: '0 auto', padding: '20px' }}>
          <Heading>Hola, {nombre}</Heading>
          <Text>Gracias por registrarte en nuestra plataforma.</Text>
          <Button href={loginUrl} style={{ backgroundColor: '#6366f1', color: '#fff', padding: '12px 24px' }}>
            Acceder a mi cuenta
          </Button>
        </Container>
      </Body>
    </Html>
  );
}
// Usar el template con Resend
import { render } from '@react-email/render';
import BienvenidaEmail from './emails/bienvenida';

async function enviarConTemplate(email: string, nombre: string) {
  const html = await render(BienvenidaEmail({ nombre, loginUrl: 'https://tuapp.com/login' }));

  return resend.emails.send({
    from: 'Fran <hola@tudominio.com>',
    to: email,
    subject: `Bienvenido, ${nombre}`,
    html,
  });
}

Opción 2: Nodemailer con SMTP

Nodemailer sigue siendo la opción estándar cuando necesitas SMTP directo (Gmail corporativo, Outlook 365, servidor propio).

npm install nodemailer
npm install -D @types/nodemailer

Configurar el transporter

import nodemailer from 'nodemailer';

// Para Gmail (requiere App Password, no la contraseña normal)
const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: process.env.GMAIL_USER,
    pass: process.env.GMAIL_APP_PASSWORD, // App Password de Google, no tu contraseña
  },
});

// Para servidor SMTP genérico (Brevo, Mailgun, etc.)
const transporter = nodemailer.createTransport({
  host: process.env.SMTP_HOST,      // smtp.brevo.com
  port: Number(process.env.SMTP_PORT), // 587
  secure: false,                     // true para 465, false para otros
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

Enviar email

async function enviarEmail(to: string, subject: string, html: string) {
  const info = await transporter.sendMail({
    from: '"Mi App" <hola@tudominio.com>',
    to,
    subject,
    html,
    // Adjunto
    attachments: [
      {
        filename: 'factura.pdf',
        path: './facturas/factura-001.pdf',
        contentType: 'application/pdf',
      },
    ],
  });

  console.log('Email enviado:', info.messageId);
  return info;
}

Configurar Gmail correctamente

Google desactivó el acceso con contraseña normal. Necesitas una App Password:

  1. Ve a tu cuenta Google → Seguridad → Verificación en dos pasos (actívala si no está)
  2. Busca “Contraseñas de aplicaciones”
  3. Genera una para “Correo” → “Otro”
  4. Esa cadena de 16 dígitos es GMAIL_APP_PASSWORD

Probar emails en desarrollo: Mailtrap

Nunca envíes emails reales en desarrollo. Usa Mailtrap:

// .env.development
SMTP_HOST=sandbox.smtp.mailtrap.io
SMTP_PORT=2525
SMTP_USER=tu_usuario_mailtrap
SMTP_PASS=tu_contraseña_mailtrap

Todos los emails que envíes aparecen en el inbox de Mailtrap sin llegar a nadie.


Entregabilidad: por qué acaban en spam

La configuración DNS es tan importante como el código. Necesitas tres registros en tu dominio:

# SPF — declara qué servidores pueden enviar en tu nombre
TXT  @  "v=spf1 include:_spf.resend.com ~all"

# DKIM — firma criptográfica de cada email
TXT  resend._domainkey  "v=DKIM1; k=rsa; p=MIGf..."  (te lo da Resend/SendGrid)

# DMARC — política para emails que fallan SPF o DKIM
TXT  _dmarc  "v=DMARC1; p=none; rua=mailto:dmarc@tudominio.com"

Si usas variables de entorno correctamente en Node.js, las claves de Resend/SMTP nunca llegarán al repositorio.

Para integrar el envío de emails con la autenticación, mira la guía de Auth.js con Next.js — el flujo de “olvide mi contraseña” usa exactamente estos patrones.

Fran Cobos

Fran Cobos

Desarrollador Full Stack especializado en IA aplicada, automatización y desarrollo web. Escribo sobre herramientas, tutoriales y casos reales para programadores.

¿Necesitas desarrollo a medida?

Apps web, IA, módulos ERP — cuéntame tu proyecto.