tutoriales·14 min de lectura

Envio de emails profesionales con Resend y React Email en NextJS

Tutorial completo para implementar un sistema de emails transaccionales usando Resend y React Email en NextJS. Aprende a enviar correos profesionales con plantillas personalizadas.

Envio de emails profesionales con Resend y React Email en NextJS

Este tutorial de Resend y React Email te muestra cómo implementar un sistema completo de emails transaccionales en NextJS. Desde la configuración inicial hasta plantillas reutilizables para confirmación de registro, restablecimiento de contraseña y notificaciones.

¿Qué son los emails transaccionales?

Los emails transaccionales son correos automatizados que se envian 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, disenado especificamente 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 (estadisticas) 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
  • Envias notificaciones importantes a usuarios
  • Quieres emails con diseño profesional
  • Necesitas hasta 100,000 emails/mes

Probablemente no lo necesitas si:

  • Solo envias emails ocasionales desde tu email personal
  • Haces campanas 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 publicamente ni la subas a GitHub. Es como una contraseña para enviar emails desde tu cuenta. Si sospechas que tus credenciales fueron comprometidas, herramientas como datahogo pueden escanear tu repositorio para detectar secrets expuestos automáticamente.

Paso 2: Instalar dependencias

bash
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

Que 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 publicamente (como tu API Key).

Crea un archivo .env.local en la raiz de tu proyecto:

bash
# .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:

plaintext
emails/
└── bienvenida.tsx
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:

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

Ejecuta:

bash
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 increiblemente ú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. Es recomendable validar los datos de entrada con Zod antes de enviar cualquier correo.

typescript
// 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 usando Fetch API. La llamada es asíncrona con async/await:

typescript
// 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('Ocurrio 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, recibira 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

tsx
// emails/verificación-email.tsx
import {
  Body,
  Button,
  Container,
  Head,
  Heading,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'
 
interface VerificacionEmailProps {
  nombreUsuario: string
  urlVerificación: string
}
 
export default function VerificacionEmail({
  nombreUsuario,
  urlVerificación
}: 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 boton de abajo:
          </Text>
 
          <Section style={buttonContainer}>
            <Button style={button} href={urlVerificación}>
              Verificar Email
            </Button>
          </Section>
 
          <Text style={text}>
            Este enlace expirara 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:

typescript
// app/api/verificar-email/route.ts
import { Resend } from 'resend'
import VerificacionEmail from '@/emails/verificación-email'
 
const resend = new Resend(process.env.RESEND_API_KEY)
 
export async function POST(request: Request) {
  const { email, nombreUsuario, token } = await request.json()
 
  const urlVerificación = `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, urlVerificación }),
  })
 
  return Response.json({ success: true })
}

2. Restablecer contraseña

tsx
// 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 tu, haz click en el boton de abajo:
          </Text>
 
          <Section style={buttonContainer}>
            <Button style={button} href={urlReset}>
              Restablecer contraseña
            </Button>
          </Section>
 
          <Text style={text}>
            Este enlace expirara en 1 hora por seguridad.
          </Text>
 
          <Text style={alertText}>
            Si NO solicitaste restablecer tu contraseña, ignora este email
            y tu contraseña permanecera 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

tsx
// emails/confirmación-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 esta 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:

tsx
// 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',
}
tsx
// 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}>
            Politica de Privacidad
          </Link>
          {' · '}
          <Link href="https://tudominio.com/términos" 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',
}

Usalos en tus emails:

tsx
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

typescript
// 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.

tsx
// 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 movil:

tsx
const container = {
  maxWidth: '600px',  // Ancho máximo para escritorio
  margin: '0 auto',
  padding: '20px',
}
 
const text = {
  fontSize: '16px',  // tamaño legible en movil
  lineHeight: '24px',  // Espaciado generoso
}

4. Call to action (CTA) claro

tsx
// 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

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

6. Enlaces seguros

tsx
// 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

typescript
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

typescript
// Nunca envies por email
- Contrasenas en texto plano
- números de tarjeta completos
- Información medica sensible
 
// Envia 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

typescript
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)

typescript
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

typescript
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

typescript
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:

typescript
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:

bash
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 envio de emails

Crea una ruta de testing que solo funcione en desarrollo:

typescript
// 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 automaticos. En tu dashboard puedes ver:

  • Emails enviados: cuántos emails envias 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 envia 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 vera
  2. Evita CSS moderno: Usa solo propiedades básicas
  3. Usa tablas para layouts complejos: Si, 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:

bash
RESEND_API_KEY=re_tu_clave_aqui

Y que estes cargando la variable correctamente:

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

Email muy lento

Problema: Tarda mucho en enviar.

Solución: Envia emails de forma asíncrona:

typescript
// 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 aun, usa una cola de trabajos (job queue) como BullMQ.

Alternativas a Resend

Si Resend no se ajusta a tus necesidades:

Servicios similares:

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

Cuando considerar alternativas:

  • Necesitas enviar millones de emails
  • Requieres funciones muy especificas
  • Ya tienes infraestructura con otro proveedor

Conclusion

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

#resend#react-email#nextjs#emails-transaccionales

Preguntas frecuentes

¿Qué ventajas tiene Resend frente a otros servicios de email como SendGrid o Mailgun?

Resend ofrece una API más simple y moderna, un plan gratuito de 3,000 emails al mes, y esta disenado especificamente para desarrolladores. además, su integración nativa con React Email permite crear plantillas con componentes de React en lugar de HTML complejo.

¿Cómo funcionan las plantillas de React Email?

React Email te permite crear plantillas de correo usando componentes de React como Body, Button, Container y Text. Estos componentes generan HTML compatible con todos los clientes de email, y puedes previsualizarlos en tiempo real con el servidor de desarrollo incluido.

¿Cómo configuró mi API Key de Resend en un proyecto NextJS?

Crea una cuenta en resend.com, genera una API Key desde el dashboard, y guardala en tu archivo .env.local como RESEND_API_KEY=tu_clave_aqui. Luego inicializa el cliente con new Resend(process.env.RESEND_API_KEY) en tus API Routes o Server Actions.