Resend API Tutorial: React Email + SDK en 5 Pasos para Dejar de Escribir HTML en Strings
Tutorial práctico de Resend con React Email: SDK, componentes JSX, preview local y testing en CI. Deja de escribir HTML en strings y trata el email como código.
La última vez que enviaste un email transaccional, probablemente escribiste HTML dentro de un string dentro de una función. Eso no es feo. Son horas perdidas cada sprint.
Resend alcanzó 100 millones de emails en su primer año. No porque tuviera mejor entregabilidad que SendGrid o Mailgun — es comparable. Creció porque resolvió el problema que nadie quería tocar: *las plantillas de email apestan, y los incumbentes nunca lo admitieron. *
SendGrid te obliga a crear templates en su dashboard, copiar un ID, y pasarlo por la API. Mailgun te da HTML plano. SES te devuelve XML — *en 2026. *
Resend hizo lo obvio que nadie hizo: trató el email como código. React Email — el framework open-source que co-crearon — tiene más de 15.000 estrellas en GitHub. No es un template engine. Es JSX con type safety, preview local, y testing en CI.
Este tutorial no es teoría. Son 5 pasos para que montéis el pipeline completo hoy.
*
1. El problema que los incumbentes esconden
El 90% de los equipos que usan SendGrid o SES tienen una carpeta `/emails` con archivos `.html` que nadie toca por miedo a romperlos.
❌ El enfoque legacy:
Abres el dashboard de SendGrid
Creas un template con un editor WYSIWYG que mutila tu CSS
Copias el template ID
En producción, pasas variables en un JSON enorme
Si algo se rompe, no hay stack trace
✅ El enfoque Resend:
Escribes un componente React con props tipadas
Lo renderizas a HTML con `render()` de `@react-email/components`
Lo envías con una llamada al SDK
Todo pasa por code review y CI
La diferencia no es técnica. Es de workflow. *Cuando el email es código, los cambios pasan por PR, se testean automáticamente, y se rollbackean como cualquier otro cambio. *
Ningún incumbente ofrece eso porque su modelo de negocio depende de mantenerte dentro de su dashboard.
*
2. El Pipeline de 5 Capas para Email como Código
Este es el framework que uso en todos mis proyectos. Lo llamo El Pipeline de 5 Capas para Email como Código. Cada capa resuelve un problema concreto, y juntas eliminan la fricción de enviar emails transaccionales.
Capa 1: SDK + Verificación de Dominio
Primero, instalad el SDK de Resend y configurad la verificación de dominio.
```bash
npm install resend
```
Código mínimo funcional:
```typescript
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({
from: 'onboarding@tudominio.com',
to: 'usuario@email.com',
subject: 'Bienvenido',
html: '<p>Hola, bienvenido a la plataforma</p>',
});
```
Tres líneas. Sin dashboard. Sin template ID. Sin XML.
Resend maneja DKIM, SPF y DMARC automáticamente cuando verificas el dominio. Añadís los registros DNS que os da la API, y en 10 minutos estáis enviando.
Comparadlo con SendGrid: crear cuenta, configurar sender authentication, crear un template en el dashboard, copiar el ID, llamar a la API con el ID + variables. *Seis pasos contra uno. *
Capa 2: React Email + Componentes
Aquí está el verdadero cambio de paradigma. React Email no es un template engine al uso. Es una librería de componentes JSX que se renderizan a HTML responsive compatible con todos los clientes de correo.
Instalad los componentes base:
```bash
npm install @react-email/components
```
Cread vuestro primer componente:
```tsx
import {
Body,
Button,
Container,
Head,
Heading,
Html,
Section,
Text,
} from '@react-email/components';
interface WelcomeEmailProps {
username: string;
verificationLink: string;
}
export const WelcomeEmail = ({
username,
verificationLink,
}: WelcomeEmailProps) => {
return (
<Html>
<Head />
<Body style={{ fontFamily: 'Arial, sans-serif' }}>
<Container>
<Heading>Bienvenido, {username}</Heading>
<Text>
Gracias por registrarte. Verifica tu email para empezar.
</Text>
<Section>
<Button
href={verificationLink}
style={{
background: '#000',
color: '#fff',
padding: '12px 24px',
borderRadius: '6px',
}}
>
Verificar Email
</Button>
</Section>
</Container>
</Body>
</Html>
);
};
---
Fijaos en lo que está pasando aquí:
Las props tienen types — TypeScript os grita si olvidáis pasar `username`
Los estilos son inline — React Email los maneja automáticamente para compatibilidad con Outlook, Gmail y Apple Mail
El `Button` se renderiza como un `<a>` con estilos inline que funcionan en todos los clientes
No hay HTML crudo. No hay strings concatenados. No hay `${variable}` dentro de una template literal
*Esto no es una plantilla. Es un componente. *
Capa 3: Preview Local
El ciclo de iteración tradicional con SendGrid es: editar template en dashboard → guardar → enviar email de prueba → esperar → ver cómo queda en Gmail → repetir.
Con React Email ejecutáis un servidor de preview local:
```bash
npx react-email dev
```
Abrid `http://localhost:3001`. Véis el componente renderizado en tiempo real. Cambiáis una prop, se actualiza al instante. Probáis cómo queda en mobile, en Outlook, en Gmail.
*Sin enviar un solo email. *
Esto suena a pequeño detalle. No lo es. Cada ciclo de preview-envío-espera con los incumbentes os cuesta 2-3 minutos. Con preview local, son milisegundos. Multiplicadlo por 20 iteraciones por template, por 10 templates, por el equipo entero. *Las horas se acumulan rápido. *
Capa 4: Renderizado + Envío
Ahora conectad el componente con Resend:
```typescript
import { render } from '@react-email/components';
import { Resend } from 'resend';
import { WelcomeEmail } from '@/emails/welcome';
const resend = new Resend(process.env.RESEND_API_KEY);
const html = render(
<WelcomeEmail
username="Ana"
verificationLink="https://tudominio.com/verificar?token=abc123"
/>
);
await resend.emails.send({
from: 'onboarding@tudominio.com',
to: 'ana@email.com',
subject: 'Bienvenida a la plataforma',
html,
});
```
Notad:
`render()` convierte el JSX a HTML plano optimizado para email
El componente recibe props reales — tipadas, verificables
El envío es una sola llamada al SDK
Cambiar el diseño del email es cambiar el componente. No entrar al dashboard.
Si tenéis un sistema legacy que solo habla SMTP, Resend también os cubre:
```typescript
import { render } from '@react-email/components';
import nodemailer from 'nodemailer';
import { WelcomeEmail } from '@/emails/welcome';
const html = render(<WelcomeEmail username="Ana" verificationLink="..." />);
const transporter = nodemailer.createTransport({
host: 'smtp.resend.com',
port: 587,
auth: {
user: process.env.RESEND_SMTP_USER,
pass: process.env.RESEND_SMTP_PASS,
},
});
await transporter.sendMail({
from: 'onboarding@tudominio.com',
to: 'ana@email.com',
subject: 'Bienvenida a la plataforma',
html,
});
---
*El pipeline de componentes no cambia. * Solo cambiáis el transporte. Eso es desacoplamiento real.
Capa 5: Testing Automatizado en CI
Aquí es donde el enfoque de "email como código" gana la partida.
Con templates en dashboard, no hay tests. Confiáis en que el editor WYSIWYG no haya mutilado el diseño. Con React Email, escribís tests como cualquier otro componente:
```typescript
import { render } from '@react-email/components';
import { describe, it, expect } from 'vitest';
import { WelcomeEmail } from './welcome';
describe('WelcomeEmail', () => {
it('renderiza el nombre de usuario', () => {
const html = render(
<WelcomeEmail
username="TestUser"
verificationLink="https://example.com"
/>
);
expect(html).toContain('TestUser');
});
it('incluye el enlace de verificación', () => {
const html = render(
<WelcomeEmail
username="TestUser"
verificationLink="https://example.com/verify"
/>
);
expect(html).toContain('https://example.com/verify');
});
it('tiene el botón de verificación', () => {
const html = render(
<WelcomeEmail
username="TestUser"
verificationLink="https://example.com"
/>
);
expect(html).toContain('Verificar Email');
});
});
```
Añadid un test de snapshot:
```typescript
it('coincide con el snapshot', () => {
const html = render(
<WelcomeEmail
username="TestUser"
verificationLink="https://example.com"
/>
);
expect(html).toMatchSnapshot();
});
---
Si alguien cambia el diseño del email sin actualizar el snapshot, el test falla en CI. *Los emails rotos no llegan a producción. *
Intentad hacer eso con el dashboard de SendGrid.
*
3. La objeción que os vais a encontrar
"Vale, pero la entregabilidad es lo que importa. Si los emails caen en spam, da igual lo bonito que sea el componente."
Es una objeción legítima. Vamos a desmontarla con datos.
Resend maneja DKIM, SPF y DMARC automáticamente. Para email transaccional — welcome emails, password resets, notificaciones — la entregabilidad es comparable a SendGrid, Mailgun y Postmark. Las diferencias son marginales cuando configuráis correctamente la autenticación.
¿Dónde ganan los incumbentes? En email marketing de alto volumen con IPs dedicadas y warmup. Si enviáis 500.000 emails promocionales al día, necesitáis Mailgun o Postmark con IP dedicada y un proceso de calentamiento.
*Pero ese no es el caso de uso del 90% de los desarrolladores que leen esto. *
El 90% envía emails transaccionales. Y para ese caso, la entregabilidad de Resend está a la par. La diferencia real está en las horas que ahorráis cada semana no peleándoos con dashboards y templates HTML en strings.
*
4. Por qué esto importa más de lo que parece
El email es infraestructura. Como las bases de datos, como la autenticación. Nadie debería pensar en ello.
Pero los incumbentes os obligan a pensar porque sus herramientas están diseñadas para equipos de marketing, no para desarrolladores. SendGrid fue adquirido por Twilio porque Twilio necesitaba email. Mailgun fue comprado por Sinch. SES es un servicio de AWS que apenas ha cambiado en 10 años.
*Ninguno compite en experiencia de desarrollador porque los desarrolladores no pagan las facturas. *
Resend sí. Y por eso creció a 100 millones de emails en su primer año. No porque reinventara el protocolo SMTP. Sino porque hizo que los desarrolladores dejaran de odiar el email.
*
5. Lo que os lleváis de este tutorial
El Pipeline de 5 Capas para Email como Código se resume en:
1. SDK + dominio — 3 líneas, verificación DNS en 10 minutos
2. Componentes React Email — JSX tipado, sin HTML crudo
3. Preview local — iteración instantánea sin enviar un email
4. Renderizado + envío — `render()` + `resend.emails.send()` en una llamada
5. Testing en CI — snapshots y tests unitarios que atrapan cambios antes de producción
El argumento de que "todos los email APIs son iguales" solo se sostiene si ignoráis el coste de mantener templates. Resend no compite en precio ni en entregabilidad. *Compite en el tiempo que le devuelve al desarrollador. *
Y ese tiempo, multiplicado por cada sprint, por cada miembro del equipo, es la diferencia entre un equipo que avanza rápido y uno que se atasca actualizando templates en un dashboard.
El email es código. Tratadlo como tal.
Lee el artículo completo en brianmenagomez.com
Más sobre mis servicios en brianmenagomez.com
Herramientas: Conversor IAE CNAE · Gestorias cerca de ti · Calculadora IRPF

