CloudflareMódulo III · Procesos y servicios · Capítulo 8 de 15Nivel: BásicoEn desarrollo

8. Email

Cómo recibir correo en tu dominio con Email Routing, procesarlo con Email Workers y enviar emails transaccionales desde un Worker o con un proveedor externo.

En desarrollo. La publico antes de terminarla porque ya puede servirte; la iré completando y anotaré los cambios al final.

Víctor Rodríguez5 min de lectura

Probado conTypeScript 7.0Wrangler 4.157Vitest 5.1

Sobres que van y vienen entre un buzón y un portátil; uno lleva el sello de verificado.

Qué vas a aprender

  • Tener direcciones de correo con tu propio dominio.
  • Convertir los correos que te llegan en datos de tu aplicación.
  • Enviar correos desde tu aplicación sin que acaben en spam.

Conocimientos iniciales

Si alguna de estas preguntas no te suena, ábrela: está explicada desde cero.

  • ¿Qué son SPF, DKIM y DMARC?

    Tres registros DNS que demuestran que un correo viene de verdad de tu dominio: SPF dice qué servidores pueden enviarlo, DKIM lo firma y DMARC indica qué hacer si algo falla. Sin ellos, tus correos acaban en spam.

  • ¿Qué es un registro DNS?Repaso

    Cada línea de esa agenda. Hay tipos: A y AAAA (dirección de un servidor), CNAME (otro nombre), MX (quién recibe tu correo) y TXT (textos para verificar o configurar servicios).

    Lo vimos en el capítulo 2.

  • ¿Qué es un dominio?Repaso

    El nombre de tu web en internet, como holaprod.dev. Se alquila por años en un registrador y es tuyo mientras lo renueves, aunque cambies de proveedor.

    Lo vimos en el capítulo 2.

El correo es de las piezas que más pereza dan en un proyecto: registros DNS, reputación del remitente, rebotes. Cloudflare cubre las dos direcciones: recibir (Email Routing, maduro y gratuito) y enviar (Email Sending, en beta en noviembre de 2026). En este capítulo monto las dos y cuento cuándo sigo usando un proveedor externo.

Para quién es y qué necesitas

Para quien quiere recibir correo en su dominio, procesarlo con código o enviar correos desde su aplicación.

Antes de empezar:

  • Un dominio en Cloudflare con su DNS (capítulo 2).
  • Para enviar desde un Worker con Email Sending: el plan de pago de Workers.
  • Una dirección tuya (Gmail, por ejemplo) donde reenviar lo que llegue.

Al terminar tendrás direcciones en tu dominio que reenvían a tu correo, un Worker que convierte correos en notas, envío de correos desde la aplicación y los registros SPF, DKIM y DMARC para no acabar en spam.

Cómo encaja el email en la aplicación

flowchart LR
    R[Remitente] -->|hola@midominio.dev| ER[Email Routing]
    ER -->|reenvío| B[Tu bandeja personal]
    ER -->|notas@midominio.dev| EW[Email Worker]
    EW --> D1[(D1)]
    API[Worker API] -->|env.EMAIL.send| ES[Email Sending]
    ES --> U[Usuario]

Recibir correo con Email Routing

En Email › Email Routing, al activarlo Cloudflare añade los registros MX y SPF necesarios. Después:

  1. Añade una dirección de destino (tu Gmail, por ejemplo) y verifícala con el correo que te llega.
  2. Crea reglas: hello@mydomain.dev → you@gmail.com.
  3. Opcional: una regla catch-all para cualquier dirección del dominio.

Procesar correo entrante con un Email Worker

En lugar de reenviar, una regla puede mandar el correo a un Worker. Así convierto los correos a notes@mydomain.dev en notas de la aplicación:

Terminal
npm install postal-mime
src/incoming-email.ts
import PostalMime from "postal-mime";
const ALLOWED = new Set(["you@gmail.com"]);
export async function incomingEmail(
message: ForwardableEmailMessage,
env: Env,
) {
if (!ALLOWED.has(message.from)) {
message.setReject("Sender not allowed");
return;
}
const email = await PostalMime.parse(message.raw);
await env.DB
.prepare(
"INSERT INTO notes (user_id, title, content) VALUES (?, ?, ?)",
)
.bind("u_1", email.subject ?? "No subject", email.text ?? "")
.run();
// Also send me a copy.
await message.forward("you@gmail.com");
}
src/index.ts (extracto)
export default {
fetch: app.fetch,
email: incomingEmail,
} satisfies ExportedHandler<Env>;

Después, en Email Routing, crea la regla notes@mydomain.dev → Send to a Worker → notes.

Enviar correo desde un Worker con Email Sending

Email Sending envía correos transaccionales (verificación de cuenta, avisos, facturas) desde tu Worker, con un binding. Al dar de alta el dominio en Compute › Email Service › Email Sending › Onboard Domain, Cloudflare crea los registros SPF, DKIM y DMARC y los MX para gestionar rebotes en el subdominio cf-bounce.

wrangler.jsonc (extracto)
{
"send_email": [{ "name": "EMAIL", "remote": true }]
}
src/send.ts
type Template = "welcome" | "reminder";
const TEMPLATES: Record<Template, { subject: string; text: string }> = {
welcome: {
subject: "Welcome to Notes",
text: "Thanks for signing up. Your first note is waiting for you.",
},
reminder: {
subject: "Shall we write the first note?",
text: "Your notebook is still empty. A title is all you need to start.",
},
};
export async function sendEmail(
env: Env,
to: string,
template: Template,
) {
const { subject, text } = TEMPLATES[template];
const response = await env.EMAIL.send({
from: { name: "Notes", email: "hello@mydomain.dev" },
to,
subject,
text,
html: `<p>${text}</p>`,
});
return response.messageId;
}

Avisos para ti, gratis

Enviar a direcciones de destino verificadas de tu propia cuenta es gratis en todos los planes, aunque solo tengas Email Routing. Es perfecto para alertas internas (“ha fallado el cron”, “nuevo usuario de pago”) sin contratar nada.

Cuándo uso un proveedor externo

Necesidad Email Sending (beta) Proveedor externo (Resend, Postmark, Amazon SES)
Correos transaccionales de una app pequeña ✅ Sin otra cuenta ni claves ✅
Plantillas con editor, analítica de aperturas Básico ✅
Volúmenes altos y reputación ya probada En beta: comprobar límites ✅
Newsletter y listas de suscriptores ❌ No es su función Usa un proveedor de newsletter

Con un proveedor externo, el envío es una llamada HTTP con su clave guardada como secreto:

src/send-external.ts
export async function sendWithResend(env: Env, to: string) {
const res = await fetch("https://api.resend.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${env.RESEND_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "Notes <hello@mydomain.dev>",
to: [to],
subject: "Welcome to Notes",
text: "Thanks for signing up.",
}),
});
if (!res.ok) throw new Error(`Resend responded ${res.status}`);
}

Que tus correos no acaben en spam

Registro Qué demuestra Ejemplo
SPF (TXT) Qué servidores pueden enviar por tu dominio v=spf1 include:… ~all
DKIM (TXT) Que el mensaje no se ha modificado y viene de ti Clave pública que te da el proveedor
DMARC (TXT en _dmarc) Qué hacer con lo que no pasa SPF/DKIM v=DMARC1; p=quarantine; rua=mailto:…

Lo que comprueba el servidor que recibe tu correo, en orden:

flowchart TD
    E[Tu correo llega] --> S{SPF: ¿este servidor puede<br/>enviar por tu dominio?}
    S --> D{DKIM: ¿la firma<br/>es de tu dominio?}
    D --> M{DMARC: ¿qué hago<br/>si algo falla?}
    M -->|Todo bien| B[Bandeja de entrada]
    M -->|Falla| X[Spam o rechazo]

Cuánto cuesta

Cuánto cuesta al mes

Supuestos: Recibir correo en el dominio y enviar avisos internos a direcciones verificadas

ConceptoImporte
Email RoutingGratis en todos los planes0,00 $
Email WorkersSe cobran como invocaciones de Workers0,00 $
Envíos a direcciones verificadasGratis0,00 $
Total al mes0,00 $

Precios consultados el 3 de noviembre de 2026. Pueden cambiar.

El envío a usuarios con Email Sending requiere el plan de pago de Workers (5 $ al mes). En noviembre de 2026, en beta, la documentación no publica un precio por correo: compruébalo antes de depender de él.

Resumen

  • Email Routing para recibir en tu dominio; Email Workers para procesar lo que llega.
  • Email Sending para enviar desde el Worker, con SPF, DKIM y DMARC configurados solos.
  • Envío desde una cola o un Workflow, no dentro de la petición: si falla, se reintenta sin que el usuario lo note.
  • Siguiente capítulo: imágenes.

Recursos

¿Te ha servido? Esto forma parte de un libro que estoy escribiendo: Cloudflare de cero a producción. Ver el índice provisional →