Blog

RA

Rod Alexanderson

Desarrollador Web

Creando documentación técnica en español para desarrolladores de Latinoamérica.

Más sobre mí →

Suscríbete al Newsletter

Recibe los nuevos artículos directamente en tu email.

Envío de emails profesionales con Resend y React Email en NextJS

Publicado el 30 de septiembre, 2025 • 14 min de lectura

Enviar emails desde tu aplicación es esencial para notificar usuarios, confirmar registros, restablecer contraseñas y más. En este tutorial aprenderás a enviar emails transaccionales profesionales usando Resend y React Email en NextJS.

¿Qué son los emails transaccionales?

Los emails transaccionales son correos automatizados que se envían en respuesta a una acción específica del usuario. A diferencia del email marketing (newsletters), estos correos son personalizados y críticos para la operación de tu aplicación.

Ejemplos de emails transaccionales:

  • ✉️ Confirmación de registro
  • 🔐 Restablecimiento de contraseña
  • 📧 Verificación de email
  • 📦 Confirmación de pedido
  • 🎉 Bienvenida a nuevos usuarios
  • 📊 Reportes o notificaciones
ℹ️

Los emails transaccionales tienen tasas de apertura del 80% comparado con ~20% de newsletters. Los usuarios esperan y necesitan recibirlos.

¿Qué son Resend y React Email?

Resend

Resend es un servicio moderno para enviar emails, diseñado específicamente para desarrolladores. Es como tener un servidor de correo profesional sin la complejidad de configurar SMTP (el protocolo tradicional para enviar emails).

Ventajas de Resend:

  • 🚀 Configuración en minutos
  • 📊 Analytics (estadísticas) incluidas
  • 💰 Plan gratuito generoso (3,000 emails/mes)
  • 🎯 Alta tasa de entrega (tus emails no van a spam)
  • 🔧 API simple y moderna

React Email

React Email es una librería que te permite crear plantillas de email usando componentes de React en lugar de escribir HTML complicado manualmente.

Ventajas de React Email:

  • ⚛️ Usa React que ya conoces
  • 🎨 Componentes reutilizables
  • 👁️ Vista previa en tiempo real
  • 📱 Emails responsive automáticamente
  • 🧪 Fácil de probar
Combinación perfecta

Resend + React Email = Emails profesionales con código limpio y mantenible

Casos de uso reales

Antes de empezar, veamos cuándo necesitas esto:

✅ Deberías usar Resend + React Email si:

  • Necesitas enviar confirmaciones de registro
  • Tienes sistema de recuperación de contraseña
  • Envías notificaciones importantes a usuarios
  • Quieres emails con diseño profesional
  • Necesitas hasta 100,000 emails/mes

❌ Probablemente no lo necesitas si:

  • Solo envías emails ocasionales desde tu email personal
  • Haces campañas de marketing masivas (usa Mailchimp, SendGrid)
  • Tienes más de 100,000 emails mensuales (considera opciones enterprise)

Configuración inicial

Paso 1: Crear cuenta en Resend

1

Ve a resend.com

Crea una cuenta gratuita con tu email o GitHub

2

Verifica tu dominio (opcional pero recomendado)

Ve a "Domains" y agrega tu dominio. Esto mejora la entrega y permite enviar desde tu@tudominio.com

Si no tienes dominio, puedes usar el dominio de prueba que Resend te proporciona

3

Crea una API Key (clave de acceso)

  1. Ve a "API Keys"
  2. Click en "Create API Key"
  3. Dale un nombre descriptivo (ej: "NextJS Production")
  4. Guarda la clave - solo se muestra una vez
⚠️
Guarda tu API Key de forma segura

Nunca compartas tu API Key públicamente ni la subas a GitHub. Es como una contraseña para enviar emails desde tu cuenta.

Paso 2: Instalar dependencias

npm install resend react-email @react-email/components
# o
yarn add resend react-email @react-email/components
# o
pnpm add resend react-email @react-email/components

¿Qué instalamos?

  • resend - Cliente para enviar emails
  • react-email - Herramientas para crear plantillas
  • @react-email/components - Componentes preconstruidos (botones, títulos, etc.)

Paso 3: Configurar variables de entorno

Las variables de entorno son valores secretos que no quieres compartir públicamente (como tu API Key).

Crea un archivo .env.local en la raíz de tu proyecto:

# .env.local
RESEND_API_KEY=re_123456789_tu_clave_aqui
💡

El archivo .env.local debe estar en tu .gitignore para que nunca se suba a GitHub. NextJS ya lo ignora por defecto.

Tu primer email

Vamos a crear un email simple de confirmación de registro.

Paso 1: Crear la plantilla del email

Crea una carpeta para tus emails:

emails/
└── bienvenida.tsx
// emails/bienvenida.tsx
import {
  Body,
  Button,
  Container,
  Head,
  Heading,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'

interface BienvenidaEmailProps {
  nombreUsuario: string
}

export default function BienvenidaEmail({ nombreUsuario }: BienvenidaEmailProps) {
  return (
    <Html>
      <Head />
      <Preview>¡Bienvenido a nuestra plataforma!</Preview>
      <Body style={main}>
        <Container style={container}>
          <Heading style={h1}>¡Hola {nombreUsuario}!</Heading>
          
          <Text style={text}>
            Gracias por registrarte en nuestra plataforma. Estamos emocionados de tenerte con nosotros.
          </Text>

          <Section style={buttonContainer}>
            <Button style={button} href="https://tudominio.com/dashboard">
              Ir al Dashboard
            </Button>
          </Section>

          <Text style={text}>
            Si tienes alguna pregunta, no dudes en contactarnos.
          </Text>

          <Text style={footer}>
            Saludos,
            <br />
            El equipo de Tu Empresa
          </Text>
        </Container>
      </Body>
    </Html>
  )
}

// Estilos inline (necesarios para emails)
const main = {
  backgroundColor: '#f6f9fc',
  fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
}

const container = {
  backgroundColor: '#ffffff',
  margin: '0 auto',
  padding: '20px 0 48px',
  marginBottom: '64px',
}

const h1 = {
  color: '#333',
  fontSize: '24px',
  fontWeight: 'bold',
  margin: '40px 0',
  padding: '0',
  textAlign: 'center' as const,
}

const text = {
  color: '#333',
  fontSize: '16px',
  lineHeight: '26px',
  textAlign: 'left' as const,
  margin: '16px 40px',
}

const buttonContainer = {
  textAlign: 'center' as const,
  margin: '32px 0',
}

const button = {
  backgroundColor: '#5469d4',
  borderRadius: '4px',
  color: '#fff',
  fontSize: '16px',
  textDecoration: 'none',
  textAlign: 'center' as const,
  display: 'inline-block',
  padding: '12px 24px',
}

const footer = {
  color: '#8898aa',
  fontSize: '12px',
  lineHeight: '16px',
  margin: '40px 40px 0',
}
ℹ️
¿Por qué estilos inline?

Los clientes de email (Gmail, Outlook, etc.) no soportan CSS moderno. Por eso usamos estilos inline directamente en cada elemento. Es tedioso, pero es la única forma confiable de que tus emails se vean bien en todos lados.

Paso 2: Vista previa del email

React Email incluye un servidor de desarrollo para ver tus emails en tiempo real.

Agrega este script a tu package.json:

{
  "scripts": {
    "email": "email dev"
  }
}

Ejecuta:

npm run email

Abre http://localhost:3000 y verás una lista de todos tus emails con vista previa en vivo. ¡Puedes editar el código y ver los cambios al instante!

La vista previa de React Email es increíblemente útil. Te ahorra el ciclo de "enviar email de prueba → revisar → editar → repetir".

Paso 3: Crear la API para enviar el email

Ahora necesitas una API Route (ruta de servidor) en NextJS para enviar el email.

// app/api/enviar-bienvenida/route.ts
import { NextResponse } from 'next/server'
import { Resend } from 'resend'
import BienvenidaEmail from '@/emails/bienvenida'

// Inicializar Resend con tu API Key
const resend = new Resend(process.env.RESEND_API_KEY)

export async function POST(request: Request) {
  try {
    // Obtener datos del cuerpo de la petición
    const { email, nombreUsuario } = await request.json()

    // Enviar el email
    const { data, error } = await resend.emails.send({
      from: 'Tu Empresa <onboarding@tudominio.com>',
      to: [email],
      subject: '¡Bienvenido a nuestra plataforma!',
      react: BienvenidaEmail({ nombreUsuario }),
    })

    if (error) {
      return NextResponse.json({ error }, { status: 400 })
    }

    return NextResponse.json({ data })
  } catch (error) {
    return NextResponse.json({ error }, { status: 500 })
  }
}
⚠️
Sobre el remitente (from)

Si no has verificado tu dominio en Resend, usa el dominio de prueba que te proporcionan. Si ya verificaste tu dominio, puedes usar cualquier dirección de tu dominio como remitente.

Paso 4: Enviar el email desde tu aplicación

Ahora puedes llamar a tu API desde cualquier parte de tu aplicación:

// app/registro/page.tsx
"use client"

import { useState } from 'react'

export default function RegistroPage() {
  const [email, setEmail] = useState('')
  const [nombre, setNombre] = useState('')
  const [enviando, setEnviando] = useState(false)

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    setEnviando(true)

    try {
      // Registrar usuario (tu lógica aquí)
      // ...

      // Enviar email de bienvenida
      const response = await fetch('/api/enviar-bienvenida', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          email,
          nombreUsuario: nombre,
        }),
      })

      if (response.ok) {
        alert('¡Registro exitoso! Revisa tu email.')
      } else {
        alert('Error al enviar email de confirmación')
      }
    } catch (error) {
      console.error('Error:', error)
      alert('Ocurrió un error')
    } finally {
      setEnviando(false)
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Nombre"
        value={nombre}
        onChange={(e) => setNombre(e.target.value)}
        required
      />
      <input
        type="email"
        placeholder="Email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <button type="submit" disabled={enviando}>
        {enviando ? 'Registrando...' : 'Registrarse'}
      </button>
    </form>
  )
}

¡Listo! Ahora cuando alguien se registre, recibirá automáticamente un email de bienvenida profesional.

Plantillas de email comunes

Veamos cómo crear emails para casos de uso comunes.

1. Verificación de email

// emails/verificacion-email.tsx
import {
  Body,
  Button,
  Container,
  Head,
  Heading,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'

interface VerificacionEmailProps {
  nombreUsuario: string
  urlVerificacion: string
}

export default function VerificacionEmail({ 
  nombreUsuario,
  urlVerificacion 
}: VerificacionEmailProps) {
  return (
    <Html>
      <Head />
      <Preview>Verifica tu dirección de email</Preview>
      <Body style={main}>
        <Container style={container}>
          <Heading style={h1}>Verifica tu email</Heading>
          
          <Text style={text}>
            Hola {nombreUsuario},
          </Text>

          <Text style={text}>
            Para completar tu registro, por favor verifica tu dirección de email 
            haciendo click en el botón de abajo:
          </Text>

          <Section style={buttonContainer}>
            <Button style={button} href={urlVerificacion}>
              Verificar Email
            </Button>
          </Section>

          <Text style={text}>
            Este enlace expirará en 24 horas por seguridad.
          </Text>

          <Text style={smallText}>
            Si no solicitaste este email, puedes ignorarlo de forma segura.
          </Text>
        </Container>
      </Body>
    </Html>
  )
}

// Estilos... (similares al ejemplo anterior)
const main = { /* ... */ }
const container = { /* ... */ }
// etc.

Uso:

// app/api/verificar-email/route.ts
import { Resend } from 'resend'
import VerificacionEmail from '@/emails/verificacion-email'

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

export async function POST(request: Request) {
  const { email, nombreUsuario, token } = await request.json()
  
  const urlVerificacion = `https://tudominio.com/verificar?token=${token}`

  await resend.emails.send({
    from: 'Tu Empresa <noreply@tudominio.com>',
    to: [email],
    subject: 'Verifica tu dirección de email',
    react: VerificacionEmail({ nombreUsuario, urlVerificacion }),
  })

  return Response.json({ success: true })
}

2. Restablecer contraseña

// emails/restablecer-password.tsx
import {
  Body,
  Button,
  Container,
  Head,
  Heading,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'

interface RestablecerPasswordProps {
  nombreUsuario: string
  urlReset: string
}

export default function RestablecerPassword({ 
  nombreUsuario,
  urlReset 
}: RestablecerPasswordProps) {
  return (
    <Html>
      <Head />
      <Preview>Restablece tu contraseña</Preview>
      <Body style={main}>
        <Container style={container}>
          <Heading style={h1}>Restablecer contraseña</Heading>
          
          <Text style={text}>
            Hola {nombreUsuario},
          </Text>

          <Text style={text}>
            Recibimos una solicitud para restablecer la contraseña de tu cuenta.
            Si fuiste tú, haz click en el botón de abajo:
          </Text>

          <Section style={buttonContainer}>
            <Button style={button} href={urlReset}>
              Restablecer Contraseña
            </Button>
          </Section>

          <Text style={text}>
            Este enlace expirará en 1 hora por seguridad.
          </Text>

          <Text style={alertText}>
            ⚠️ Si NO solicitaste restablecer tu contraseña, ignora este email 
            y tu contraseña permanecerá sin cambios.
          </Text>
        </Container>
      </Body>
    </Html>
  )
}

const alertText = {
  color: '#d9534f',
  fontSize: '14px',
  lineHeight: '24px',
  margin: '24px 40px',
  padding: '12px',
  backgroundColor: '#f9f2f2',
  borderRadius: '4px',
}

// Otros estilos...

3. Confirmación de pedido

// emails/confirmacion-pedido.tsx
import {
  Body,
  Container,
  Head,
  Heading,
  Hr,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'

interface Producto {
  nombre: string
  cantidad: number
  precio: number
}

interface ConfirmacionPedidoProps {
  nombreUsuario: string
  numeroPedido: string
  productos: Producto[]
  total: number
}

export default function ConfirmacionPedido({
  nombreUsuario,
  numeroPedido,
  productos,
  total,
}: ConfirmacionPedidoProps) {
  return (
    <Html>
      <Head />
      <Preview>Tu pedido #{numeroPedido} ha sido confirmado</Preview>
      <Body style={main}>
        <Container style={container}>
          <Heading style={h1}>¡Pedido confirmado!</Heading>
          
          <Text style={text}>
            Hola {nombreUsuario},
          </Text>

          <Text style={text}>
            Gracias por tu compra. Tu pedido #{numeroPedido} ha sido confirmado 
            y está siendo procesado.
          </Text>

          <Section style={productContainer}>
            <Text style={productTitle}>Resumen del pedido:</Text>
            
            {productos.map((producto, index) => (
              <div key={index} style={productRow}>
                <Text style={productName}>
                  {producto.nombre} x{producto.cantidad}
                </Text>
                <Text style={productPrice}>
                  ${producto.precio.toFixed(2)}
                </Text>
              </div>
            ))}

            <Hr style={hr} />

            <div style={productRow}>
              <Text style={totalLabel}>Total:</Text>
              <Text style={totalAmount}>${total.toFixed(2)}</Text>
            </div>
          </Section>

          <Text style={text}>
            Te enviaremos otro email cuando tu pedido sea enviado.
          </Text>
        </Container>
      </Body>
    </Html>
  )
}

const productContainer = {
  margin: '32px 40px',
  padding: '16px',
  backgroundColor: '#f6f9fc',
  borderRadius: '4px',
}

const productTitle = {
  fontSize: '14px',
  fontWeight: 'bold',
  color: '#333',
  marginBottom: '16px',
}

const productRow = {
  display: 'flex',
  justifyContent: 'space-between',
  marginBottom: '8px',
}

const productName = {
  fontSize: '14px',
  color: '#555',
}

const productPrice = {
  fontSize: '14px',
  color: '#333',
  fontWeight: 'bold',
}

const hr = {
  margin: '16px 0',
  border: 'none',
  borderTop: '1px solid #ddd',
}

const totalLabel = {
  fontSize: '16px',
  fontWeight: 'bold',
  color: '#333',
}

const totalAmount = {
  fontSize: '18px',
  fontWeight: 'bold',
  color: '#5469d4',
}

// Otros estilos...

Componentes reutilizables

Puedes crear tus propios componentes para reutilizar en múltiples emails:

// emails/components/Header.tsx
import { Img, Section } from '@react-email/components'

interface HeaderProps {
  logoUrl: string
}

export function Header({ logoUrl }: HeaderProps) {
  return (
    <Section style={header}>
      <Img
        src={logoUrl}
        width="150"
        height="50"
        alt="Logo"
        style={logo}
      />
    </Section>
  )
}

const header = {
  textAlign: 'center' as const,
  padding: '20px 0',
  borderBottom: '1px solid #eee',
}

const logo = {
  margin: '0 auto',
}
// emails/components/Footer.tsx
import { Hr, Link, Section, Text } from '@react-email/components'

export function Footer() {
  return (
    <>
      <Hr style={hr} />
      <Section style={footer}>
        <Text style={footerText}>
          © 2025 Tu Empresa. Todos los derechos reservados.
        </Text>
        <Text style={footerLinks}>
          <Link href="https://tudominio.com/privacidad" style={link}>
            Política de Privacidad
          </Link>
          {' · '}
          <Link href="https://tudominio.com/terminos" style={link}>
            Términos de Servicio
          </Link>
        </Text>
      </Section>
    </>
  )
}

const hr = {
  margin: '32px 0',
  borderColor: '#ddd',
}

const footer = {
  textAlign: 'center' as const,
  padding: '20px 40px',
}

const footerText = {
  fontSize: '12px',
  color: '#8898aa',
}

const footerLinks = {
  fontSize: '12px',
  color: '#8898aa',
  marginTop: '8px',
}

const link = {
  color: '#5469d4',
  textDecoration: 'underline',
}

Úsalos en tus emails:

import { Header } from './components/Header'
import { Footer } from './components/Footer'

export default function MiEmail() {
  return (
    <Html>
      <Body>
        <Container>
          <Header logoUrl="https://tudominio.com/logo.png" />
          
          {/* Contenido del email */}
          
          <Footer />
        </Container>
      </Body>
    </Html>
  )
}

Mejores prácticas

1. Asunto claro y directo

// ❌ Malo
subject: 'Información importante'

// ✅ Bueno
subject: 'Confirma tu dirección de email'
subject: 'Tu pedido #12345 ha sido enviado'
subject: 'Restablece tu contraseña - Expira en 1 hora'

2. Preview text efectivo

El texto de vista previa aparece junto al asunto en la bandeja de entrada.

// ❌ Malo - no informativo
<Preview>Email de nuestra empresa</Preview>

// ✅ Bueno - complementa el asunto
<Preview>Haz click en el enlace para verificar tu cuenta en 5 segundos</Preview>

3. Diseño responsive

Los componentes de React Email son responsive por defecto, pero asegúrate de probar en móvil:

const container = {
  maxWidth: '600px',  // Ancho máximo para escritorio
  margin: '0 auto',
  padding: '20px',
}

const text = {
  fontSize: '16px',  // Tamaño legible en móvil
  lineHeight: '24px',  // Espaciado generoso
}

4. Call to action (CTA) claro

// ✅ Un solo CTA principal por email
<Button href={url}>
  Verificar mi cuenta ahora
</Button>

// ❌ Evita múltiples CTAs que confunden

5. Textos alternativos para imágenes

<Img 
  src="logo.png" 
  alt="Logo de Tu Empresa"  // Importante para accesibilidad
  width="150"
  height="50"
/>

6. Enlaces seguros

// ✅ Enlaces absolutos (completos)
<Link href="https://tudominio.com/settings">
  Configuración
</Link>

// ❌ Enlaces relativos no funcionan en emails
<Link href="/settings">Configuración</Link>

7. Manejo de errores

try {
  const { data, error } = await resend.emails.send({
    // ...configuración
  })

  if (error) {
    console.error('Error de Resend:', error)
    // Notifica al usuario o registra en sistema de logs
    return NextResponse.json(
      { error: 'No se pudo enviar el email' }, 
      { status: 500 }
    )
  }

  return NextResponse.json({ success: true, data })
} catch (error) {
  console.error('Error inesperado:', error)
  return NextResponse.json(
    { error: 'Error del servidor' },
    { status: 500 }
  )
}

8. No enviar información sensible

// ❌ Nunca envíes por email
- Contraseñas en texto plano
- Números de tarjeta completos
- Información médica sensible

// ✅ Envía enlaces seguros a tu aplicación
- Token de un solo uso para restablecer contraseña
- Enlace a dashboard para ver información sensible

Funcionalidades avanzadas

Enviar a múltiples destinatarios

await resend.emails.send({
  from: 'Tu Empresa <noreply@tudominio.com>',
  to: ['usuario1@ejemplo.com', 'usuario2@ejemplo.com'],
  subject: 'Email para varios usuarios',
  react: MiEmail(),
})

Copia oculta (BCC)

await resend.emails.send({
  from: 'Tu Empresa <noreply@tudominio.com>',
  to: ['usuario@ejemplo.com'],
  bcc: ['admin@tudominio.com'], // Copia oculta al admin
  subject: 'Confirmación de pedido',
  react: ConfirmacionPedido(props),
})

Adjuntar archivos

await resend.emails.send({
  from: 'Tu Empresa <noreply@tudominio.com>',
  to: ['usuario@ejemplo.com'],
  subject: 'Tu factura',
  react: EmailFactura(),
  attachments: [
    {
      filename: 'factura.pdf',
      content: Buffer.from(pdfData),
    },
  ],
})

Responder a dirección diferente

await resend.emails.send({
  from: 'Tu Empresa <noreply@tudominio.com>',
  to: ['usuario@ejemplo.com'],
  replyTo: 'soporte@tudominio.com', // Las respuestas van aquí
  subject: 'Contacto de soporte',
  react: EmailSoporte(),
})

Tags para organización

Los tags te ayudan a organizar y filtrar emails en el dashboard de Resend:

await resend.emails.send({
  from: 'Tu Empresa <noreply@tudominio.com>',
  to: ['usuario@ejemplo.com'],
  subject: 'Bienvenida',
  react: BienvenidaEmail(),
  tags: [
    { name: 'category', value: 'onboarding' },
    { name: 'user_type', value: 'free' },
  ],
})

Testing (pruebas)

Probar emails localmente

React Email incluye un servidor de desarrollo:

npm run email

Esto abre una interfaz donde puedes:

  • Ver todos tus emails
  • Probar con diferentes datos
  • Ver cómo se ven en diferentes clientes
  • Copiar el HTML generado

Probar envío de emails

Crea una ruta de testing que solo funcione en desarrollo:

// app/api/test-email/route.ts
import { NextResponse } from 'next/server'
import { Resend } from 'resend'
import BienvenidaEmail from '@/emails/bienvenida'

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

export async function GET() {
  // Solo permitir en desarrollo
  if (process.env.NODE_ENV !== 'development') {
    return NextResponse.json({ error: 'No autorizado' }, { status: 403 })
  }

  try {
    const { data, error } = await resend.emails.send({
      from: 'Test <onboarding@resend.dev>',
      to: ['tu-email@ejemplo.com'], // Tu email de prueba
      subject: 'Email de prueba',
      react: BienvenidaEmail({ nombreUsuario: 'Usuario de Prueba' }),
    })

    return NextResponse.json({ success: true, data })
  } catch (error) {
    return NextResponse.json({ error }, { status: 500 })
  }
}

Visita http://localhost:3000/api/test-email para enviar un email de prueba.

Monitoreo y analytics

Resend incluye analytics automáticos. En tu dashboard puedes ver:

  • 📊 Emails enviados: Cuántos emails envías diariamente
  • Entregados: Cuántos llegaron exitosamente
  • 📧 Abiertos: Cuántos usuarios abrieron el email
  • 🖱️ Clicks: Cuántos hicieron click en tus enlaces
  • Rebotes: Emails que no se pudieron entregar
  • 🚫 Spam: Emails marcados como spam
💡

Una tasa de apertura del 15-25% es normal para emails transaccionales. Si es menor, revisa tus asuntos y remitente.

Costos y límites

Plan Gratuito

  • 3,000 emails/mes
  • 100 emails/día
  • Todas las funciones incluidas
  • Perfecto para proyectos pequeños y testing

Plan Pro ($20/mes)

  • 50,000 emails/mes
  • Sin límite diario
  • Soporte prioritario
  • Ideal para aplicaciones en crecimiento

Plan Enterprise

  • Contactar para precios
  • Millones de emails
  • Soporte dedicado
  • Para aplicaciones grandes
ℹ️

Compara estos precios con SendGrid ($15/mes por 15,000 emails) o Mailgun ($35/mes por 50,000). Resend es muy competitivo.

Troubleshooting (Solución de problemas)

Email no llega

Problema: El email se envía pero no llega.

Soluciones:

  1. Revisa spam/correo no deseado
  2. Verifica el remitente: Si no verificaste tu dominio, usa el dominio de prueba
  3. Revisa el dashboard de Resend: Verás si hubo errores
  4. Email bloqueado: Algunos proveedores (como Outlook) pueden ser estrictos

Email se ve raro

Problema: El diseño no se ve como esperabas.

Soluciones:

  1. Usa la vista previa de React Email para ver cómo se verá
  2. Evita CSS moderno: Usa solo propiedades básicas
  3. Usa tablas para layouts complejos: Sí, como en los 90s
  4. Prueba en múltiples clientes: Gmail, Outlook, Apple Mail

Error al enviar

Problema: Error: Invalid API key

Solución: Verifica que tu .env.local tenga la clave correcta:

RESEND_API_KEY=re_tu_clave_aqui

Y que estés cargando la variable correctamente:

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

Email muy lento

Problema: Tarda mucho en enviar.

Solución: Envía emails de forma asíncrona:

// ❌ Malo - el usuario espera
await resend.emails.send(...)
return NextResponse.json({ success: true })

// ✅ Bueno - responde inmediatamente
resend.emails.send(...) // Sin await
return NextResponse.json({ success: true, message: 'Email en proceso' })

O mejor aún, usa una cola de trabajos (job queue) como BullMQ.

Alternativas a Resend

Si Resend no se ajusta a tus necesidades:

Servicios similares:

  • SendGrid - Más establecido, más caro
  • Mailgun - Para volúmenes muy altos
  • Postmark - Especializado en transaccionales
  • AWS SES - Muy barato pero complejo de configurar

Cuándo considerar alternativas:

  • Necesitas enviar millones de emails
  • Requieres funciones muy específicas
  • Ya tienes infraestructura con otro proveedor

Conclusión

Resend + React Email te permiten enviar emails profesionales desde tu aplicación NextJS con:

✅ Código limpio y mantenible (React que ya conoces)
✅ Vista previa en tiempo real
✅ Alta tasa de entrega
✅ Analytics incluidos
✅ Precio razonable

Siguiente paso: Implementa tu primer email de bienvenida siguiendo este tutorial, y expande a otros casos de uso según necesites.


Recursos adicionales

¿Implementaste emails en tu proyecto? Comparte tu experiencia en los comentarios.


Sobre el autor: Soy un desarrollador web especializado en NextJS y React. Creo documentación técnica en español para ayudar a la comunidad de desarrolladores en Latinoamérica.