Enviar Emails con Resend
La función principal de Resend es resend.emails.send(). Recibe un objeto con los datos del email y te devuelve el ID del mensaje o un error. Así de simple.
Anatomía de la función
const { data, error } = await resend.emails.send({
// Obligatorios
from: 'Nombre <email@tudominio.com>',
to: ['destinatario@email.com'],
subject: 'Asunto del email',
// Contenido (al menos uno es obligatorio)
html: '<p>Contenido HTML</p>',
// O: react: <MiComponente />,
// O: text: 'Contenido en texto plano',
// Opcionales
cc: ['copia@email.com'],
bcc: ['copia-oculta@email.com'],
replyTo: 'responder-a@email.com',
headers: { 'X-Custom-Header': 'valor' },
attachments: [],
tags: [{ name: 'tipo', value: 'bienvenida' }],
scheduledAt: 'in 1 hour',
})Parámetros obligatorios
from (string)
La dirección del remitente. El formato recomendado incluye el nombre y el email entre corchetes angulares:
from: 'Mi App <notificaciones@midominio.com>'El dominio del email debe estar verificado en tu cuenta de Resend. Para pruebas puedes usar @resend.dev.
El campo from debe usar un dominio verificado
Si intentas enviar desde un dominio que no has verificado en Resend, la API te devuelve un error de validación. El único dominio que funciona sin verificar es resend.dev, que Resend te proporciona para testing.
to (string | string[])
La dirección o direcciones del destinatario. Puedes pasar un string o un array:
// Un destinatario
to: 'usuario@email.com'
// Múltiples destinatarios
to: ['usuario1@email.com', 'usuario2@email.com', 'usuario3@email.com']subject (string)
El asunto del email. No tiene límite de caracteres pero los clientes de correo típicamente muestran entre 40 y 60 caracteres en la vista previa.
Contenido: html, react o text
Necesitas proporcionar al menos una forma de contenido:
HTML directo:
const { data, error } = await resend.emails.send({
from: 'Mi App <noreply@midominio.com>',
to: ['usuario@email.com'],
subject: 'Confirmación de cuenta',
html: `
<h1>Bienvenido a Mi App</h1>
<p>Tu cuenta ha sido creada exitosamente.</p>
<a href="https://miapp.com/verificar?token=abc123">Verificar email</a>
`
})Componente de React Email:
import { WelcomeEmail } from '@/emails/welcome'
const { data, error } = await resend.emails.send({
from: 'Mi App <noreply@midominio.com>',
to: ['usuario@email.com'],
subject: 'Bienvenido',
react: WelcomeEmail({ nombre: 'Carlos' })
})Texto plano:
const { data, error } = await resend.emails.send({
from: 'Mi App <noreply@midominio.com>',
to: ['usuario@email.com'],
subject: 'Tu código de verificación',
text: 'Tu código de verificación es: 482910. Expira en 10 minutos.'
})Usa tags para organizar tus analytics
El parámetro tags te permite categorizar emails en el dashboard de Resend. Por ejemplo, puedes etiquetar emails como tipo: bienvenida, tipo: factura o tipo: reset-password para filtrar métricas por categoría.
Parámetros opcionales
| Parámetro | Tipo | Descripción |
|---|---|---|
cc | string | string[] | Direcciones en copia (CC -- Carbon Copy) |
bcc | string | string[] | Direcciones en copia oculta (BCC -- Blind Carbon Copy) |
replyTo | string | string[] | Dirección de respuesta (si es diferente al from) |
headers | Record<string, string> | Headers HTTP personalizados |
attachments | Attachment[] | Archivos adjuntos |
tags | Tag[] | Etiquetas para analytics |
scheduledAt | string | Programar envío futuro |
El objeto de respuesta
Cuando el envío es exitoso, data contiene el ID del email:
// Envío exitoso
{
data: {
id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
},
error: null
}El id es el identificador único del email en Resend. Lo usas para:
- Consultar el estado del email via la API
- Cancelar un email programado
- Correlacionar con eventos de webhooks
Cuando hay un error, error contiene los detalles:
// Error
{
data: null,
error: {
statusCode: 422,
message: 'The "to" field is required.',
name: 'validation_error'
}
}Manejo de errores
Los errores más comunes que vas a encontrar:
| Error | Causa | Solución |
|---|---|---|
validation_error | Faltan campos obligatorios o el formato es inválido | Revisa que from, to, subject y al menos un tipo de contenido estén presentes |
not_found | El dominio no está verificado | Verifica tu dominio en el dashboard de Resend |
rate_limit_exceeded | Superaste el límite de requests por segundo | Implementa retry con backoff exponencial |
unauthorized | API key inválida o expirada | Verifica tu API key en Settings > API Keys |
internal_server_error | Error interno de Resend | Reintenta después de unos segundos |
Un patrón robusto para manejar errores:
import { resend } from '@/lib/resend'
async function enviarEmail(destinatario: string, asunto: string, contenido: string) {
const { data, error } = await resend.emails.send({
from: 'Mi App <noreply@midominio.com>',
to: [destinatario],
subject: asunto,
html: contenido,
})
if (error) {
console.error(`Error enviando email a ${destinatario}:`, error.message)
throw new Error(`Falló el envío: ${error.name} - ${error.message}`)
}
console.log(`Email enviado exitosamente. ID: ${data.id}`)
return data.id
}Enviar a múltiples destinatarios
Puedes enviar el mismo email a varias personas pasando un array en to:
const { data, error } = await resend.emails.send({
from: 'Mi App <noreply@midominio.com>',
to: ['usuario1@email.com', 'usuario2@email.com', 'usuario3@email.com'],
subject: 'Actualización importante',
html: '<p>Tenemos novedades para compartir.</p>'
})Todos los destinatarios reciben el mismo email y pueden ver las direcciones de los demás. Si quieres que cada destinatario solo vea su propia dirección, usa el envío en lote (batch) que cubrimos más adelante.