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
Ve a resend.com
Crea una cuenta gratuita con tu email o GitHub
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
Crea una API Key (clave de acceso)
- Ve a "API Keys"
- Click en "Create API Key"
- Dale un nombre descriptivo (ej: "NextJS Production")
- 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 emailsreact-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:
- Revisa spam/correo no deseado
- Verifica el remitente: Si no verificaste tu dominio, usa el dominio de prueba
- Revisa el dashboard de Resend: Verás si hubo errores
- Email bloqueado: Algunos proveedores (como Outlook) pueden ser estrictos
Email se ve raro
Problema: El diseño no se ve como esperabas.
Soluciones:
- Usa la vista previa de React Email para ver cómo se verá
- Evita CSS moderno: Usa solo propiedades básicas
- Usa tablas para layouts complejos: Sí, como en los 90s
- 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.