Cuando entra un pedido en un sitio de comercio electrónico de Webflow, el correo de confirmación puede hacer mucho más que solo confirmar. Con SendGrid y un Cloudflare Worker, puedes crear plantillas completas, completarlas de forma dinámica y aplicar toda la lógica condicional que tu tienda necesite.
El correo de confirmación de pedido nativo de Webflow cumple bien con lo básico. Se envía automáticamente con cada compra, hace llegar el recibo al cliente y no requiere configuración. Pero si necesitas una personalización profunda, te hace falta algo más.
El editor de plantillas te permite ajustar colores y textos, pero la estructura es fija. Las imágenes de producto dinámicas, los mensajes condicionales según el valor del pedido y las plantillas separadas para distintas líneas o niveles de productos requieren salir del sistema de correo nativo de Webflow, y ahí es donde entra en juego SendGrid.
Esta guía cubre tres caminos para lograrlo y luego explica paso a paso la implementación con Cloudflare Worker. Es el enfoque que te da control total sobre la plantilla de correo, el dominio del remitente y cualquier lógica condicional.
4 formas de enviar correos de confirmación de pedido personalizados desde Webflow
Existen cuatro enfoques, que van desde la automatización sin código hasta el control programático total. Los tres utilizan SendGrid como proveedor de correo. La elección correcta depende de cuánta personalización necesites y de si tu equipo sabe programar.
Los tres requieren una cuenta de SendGrid:
Esta guía cubre al detalle la ruta de Cloudflare Worker. Te ofrece un control total sobre la plantilla de correo, el dominio del remitente y cualquier lógica condicional; cosas que las plataformas de automatización no permiten gestionar a nivel de campo.
¿Qué necesitas para enviar correos de confirmación de pedido desde Webflow con SendGrid?
Para que la integración funcione, deben cumplirse cuatro requisitos: un sitio de comercio electrónico en Webflow, un dominio de remitente verificado en SendGrid, una clave API de SendGrid con permisos limitados y una cuenta de Cloudflare para el Worker.
Si falta alguno de estos elementos, la integración no se activará o los correos terminarán en la carpeta de spam.
Sitio de Webflow con un plan de comercio electrónico
Las funciones nativas de comercio electrónico de Webflow, incluido el ecomm_new_order activador de webhook, solo están disponibles en los planes de sitio E-commerce. Si tu sitio utiliza un plan CMS o Business estándar y emplea un sistema de pago de terceros (Stripe, botón de compra de Shopify, etc.), el webhook de comercio electrónico no se activará.
Confirma tu plan en la Configuración del proyecto antes de continuar.
Cuenta de SendGrid con un dominio de remitente verificado
Es muy probable que los correos enviados desde un dominio no verificado acaben en spam. SendGrid exige que verifiques tu dominio de envío para que los correos transaccionales lleguen a la bandeja de entrada de forma fiable. Esto implica añadir registros DNS (entradas CNAME) en tu proveedor de dominio.
Un apunte importante sobre los precios de SendGrid antes de empezar: SendGrid eliminó su plan gratuito en julio de 2025. Existe una prueba de 60 días (100 correos al día), pero después necesitarás un plan de pago. El plan Essentials comienza en 19,95 $/mes para hasta 50 000 correos, o 34,95 $/mes para hasta 100 000 correos.
Si estás haciendo pruebas con una sola dirección en lugar de con un dominio completo, la verificación de remitente único de SendGrid sirve para el desarrollo, pero no es adecuada para volúmenes de producción.
Clave de API de SendGrid con permiso de envío de correo (Mail Send)
Crea una clave de API restringida en SendGrid en Configuración → Claves de API. Al configurar los permisos, habilita Mail Send → Acceso completo. No utilices una clave de acceso completo en producción.
Una clave con alcance limitado reduce el impacto en caso de que las credenciales queden expuestas.
Cuenta de Cloudflare (el plan gratuito es suficiente)
Aquí se aplica la misma configuración de cuenta de Cloudflare y CLI de Wrangler que se usa para cualquier despliegue de Worker. El plan gratuito ofrece 100 000 solicitudes al día; más que suficiente para cualquier volumen de pedidos realista. Si ya tienes un Worker ejecutándose desde otra integración, este se desplegará como un Worker independiente en una URL distinta.
Una vez que los cuatro elementos estén listos, la configuración toma alrededor de una hora. Aquí tienes el proceso completo.
5 pasos para enviar correos de confirmación de pedidos desde Webflow con SendGrid
La integración conecta tres sistemas: Webflow activa un webhook con cada pedido nuevo, un Cloudflare Worker recibe ese webhook y procesa los datos del pedido, y SendGrid envía el correo de confirmación usando una plantilla que tú controlas.
El Worker actúa como la capa intermedia segura. Mantiene tu clave de API de SendGrid fuera del cliente y gestiona el formato de los datos antes de enviar el correo.
1. Verifica tu dominio de remitente en SendGrid
Inicia sesión en tu cuenta de SendGrid, ve a Configuración → Autenticación de remitente y haz clic en Autenticar tu dominio.
SendGrid te pedirá que selecciones tu proveedor de DNS en un menú desplegable. Elige tu registrador (Cloudflare DNS, GoDaddy, Namecheap, Route 53, etc.) o selecciona "Otro" si el tuyo no aparece en la lista.
Introduce el dominio desde el que realizarás los envíos; normalmente, tu dominio principal (yourcompany.com) o un subdominio transaccional dedicado (mail.yourcompany.com). Con la Seguridad automatizada activada (la opción predeterminada), SendGrid genera cuatro registros DNS: tres registros CNAME para el enrutamiento de correo y la marca de enlaces, además de un registro TXT para DMARC.
Añade los cuatro registros DNS a tu proveedor de DNS exactamente como se muestran. No modifiques los valores. Luego, haz clic en Verificar en SendGrid.
La propagación de DNS suele completarse en un plazo de 5 a 30 minutos. Si la verificación falla, espera 10 minutos e inténtalo de nuevo. La causa más común de error es un valor CNAME que ha sido modificado o truncado por el campo de entrada del proveedor de DNS.
Resultado esperado: SendGrid mostrará una insignia verde de "Verificado" junto a tu dominio. Todos los correos enviados desde ese dominio pasarán las comprobaciones SPF y DKIM, que es el factor principal para evitar las carpetas de spam.
2. Crea una plantilla dinámica de SendGrid para el correo de pedido
Las plantillas dinámicas de SendGrid separan la estructura visual del correo de los datos que lo completan. Diseñas la plantilla una vez y luego pasas los datos específicos del pedido (nombre del cliente, artículos, totales) desde el Worker cada vez que llega un pedido.
La plantilla utiliza sintaxis Handlebars para las variables: {{customerName}}, {{orderId}}, y {{#each lineItems}} para iterar sobre los productos.
Ve a API de correo electrónico → Plantillas dinámicas en la barra lateral de SendGrid. Haz clic en Crear una plantilla dinámica, asígnale un nombre como "Confirmación de pedido" y luego haz clic en Añadir versión para abrir el editor de plantillas.
Elige Code Editor si te sientes cómodo con HTML, o Design Editor para un diseño de arrastrar y soltar. Para un correo electrónico de pedido de producción, el Code Editor te ofrece un control más preciso sobre la estructura HTML y garantiza que tu diseño se visualice de forma coherente en todos los clientes de correo.
Una plantilla de confirmación de pedido minimalista que utiliza Handlebars:
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: sans-serif; color: #111; max-width: 600px; margin: 0 auto; }
.header { background: #1a1a2e; color: #fff; padding: 24px; }
.section { padding: 24px; }
.item-row { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #eee; }
.total-row { display: flex; justify-content: space-between; padding: 16px 0; font-weight: bold; }
</style>
</head>
<body>
<div class="header">
<h1>Order Confirmed</h1>
<p>Order #{{orderId}}</p>
</div>
<div class="section">
<p>Hi {{customerName}},</p>
<p>Your order is confirmed. Here's what you ordered:</p>
{{#each lineItems}}
<div class="item-row">
<span>{{this.name}} × {{this.quantity}}</span>
<span>${{this.price}}</span>
</div>
{{/each}}
<div class="total-row">
<span>Total</span>
<span>${{orderTotal}}</span>
</div>
</div>
<div class="section">
<p>Questions? Reply to this email or visit our <a href="{{supportUrl}}">support page</a>.</p>
</div>
</body>
</html>
Después de guardar la plantilla, copia el Template ID. Es una cadena que comienza con d- y se muestra en la parte superior de la página de detalles de la plantilla. Lo usarás como referencia en el Worker como un secreto de entorno.
Resultado esperado: La plantilla se guarda en SendGrid con un Template ID. Al previsualizarla con datos de muestra, verás las variables de Handlebars correctamente completadas con valores de marcador de posición.
3. Despliega un Cloudflare Worker para recibir el webhook y llamar a SendGrid
El Worker es un script ligero que actúa como puente entre Webflow y SendGrid. Recibe el webhook POST entrante, analiza los datos del pedido, los formatea para la plantilla de SendGrid y envía el correo. Además, mantiene tu clave API fuera del cliente. Nada confidencial queda expuesto al navegador.
Asegúrate de haber iniciado sesión en Cloudflare antes de ejecutar los siguientes comandos: npx wrangler login. Wrangler se instala localmente mediante el comando de andamiaje en el siguiente paso; no es necesaria una instalación global.
Crea la estructura de un nuevo Worker:
npm create cloudflare@latest -- order-confirmation
Selecciona "Hello World example", "Worker only" y "JavaScript".
Elige "No" cuando se te pregunte si deseas desplegarlo inmediatamente.
cd order-confirmation
Reemplaza src/index.js con este Worker:
export default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
let payload;
try {
payload = await request.json();
} catch {
return new Response('Invalid JSON payload', { status: 400 });
}
const { customerInfo, purchasedItems, totals, orderId } = payload.payload;
// Guard: Webflow always sends customerInfo.email, but defensive check is good practice
if (!customerInfo?.email) {
console.error('Missing customer email in webhook payload:', JSON.stringify(payload));
return new Response(JSON.stringify({ error: 'No customer email in payload' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}
// Price values from Webflow are numeric strings representing cents (e.g., "1999" = $19.99) — cast with Number() before dividing
const lineItems = (purchasedItems || []).map(item => ({
name: item.productName || 'Product',
quantity: item.count || 1,
price: ((Number(item.variantPrice?.value) || 0) / 100).toFixed(2),
image: item.variantImage?.url || null,
}));
const orderTotal = ((Number(totals?.total?.value) || 0) / 100).toFixed(2); // totals.total includes tax and shipping; totals.subtotal does not
const sgResponse = await fetch('https://api.sendgrid.com/v3/mail/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.SENDGRID_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
personalizations: [
{
to: [{ email: customerInfo.email, name: customerInfo.fullName }],
dynamic_template_data: {
customerName: customerInfo.fullName || 'Customer',
orderId: orderId || 'N/A',
lineItems,
orderTotal,
supportUrl: env.SUPPORT_URL || 'https://yoursite.com/support',
},
},
],
from: {
email: env.FROM_EMAIL,
name: env.FROM_NAME,
},
template_id: env.SENDGRID_TEMPLATE_ID,
}),
});
if (!sgResponse.ok) {
const errorBody = await sgResponse.text();
console.error('SendGrid error:', sgResponse.status, errorBody);
return new Response(
JSON.stringify({ error: 'Email send failed', details: errorBody }),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
return new Response(JSON.stringify({ success: true, orderId }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
},
};
Dos cosas a tener en cuenta sobre el mapeo de la carga útil (payload).
- Primero, el campo de matriz dentro de payload.payload es purchasedItems, no un orderItems genérico. Ten en cuenta la estructura de dos niveles: el cuerpo del webhook sin procesar es { triggerType, payload: { ... } }; desestructura desde payload.payload, no desde el cuerpo de nivel superior.
- Segundo, los valores de precio son cadenas numéricas que representan centavos:
"1999"significa 19,99 $. Dividir por 100 y llamar a.toFixed(2)lo convierte en una cadena lista para mostrar.
Cada artículo en purchasedItems también incluye un campo variantImage.url . La URL de la imagen se asigna a lineItems aquí para que puedas mostrar miniaturas de productos directamente en tu plantilla de SendGrid.
Añade la verificación de firma del webhook antes de pasar a producción. Webflow incluye una cabecera x-webflow-signature con cada solicitud de webhook. Verifícala en el Worker antes de procesar la carga útil para evitar solicitudes falsificadas.
La documentación para desarrolladores de Webflow cubre el patrón de verificación HMAC-SHA256. Esta es una configuración única que debe estar lista antes de que se procese el primer pedido real de un cliente.
Ahora añade tus secretos:
npx wrangler secret put SENDGRID_API_KEY
npx wrangler secret put SENDGRID_TEMPLATE_ID
npx wrangler secret put FROM_EMAIL
npx wrangler secret put FROM_NAME
npx wrangler secret put SUPPORT_URL
Introduce cada valor cuando se te solicite. FROM_EMAIL debe ser una dirección en tu dominio verificado de SendGrid. SENDGRID_TEMPLATE_ID es la cadena d- del paso 2.
Despliega:
npx wrangler deploy
Copia la URL del Worker desde el resultado: https://order-confirmation.<your-subdomain>.workers.dev. Este es el endpoint al que Webflow enviará la solicitud POST.
Resultado esperado: El Worker está activo y devuelve un error 405 para las solicitudes que no sean POST. Los secretos se almacenan con valores enmascarados en el panel de control de Cloudflare, en Workers & Pages → tu worker → Configuración → Variables y secretos.
4. Registra el webhook de pedido en Webflow
La forma más sencilla de registrar un webhook es hacerlo directamente en la configuración del sitio de Webflow. Ve a Configuración del proyecto → Integraciones → Webhooks, haz clic en Añadir webhook, selecciona ecomm_new_order como tipo de activador y pega la URL de tu Worker como destino. No se necesitan llamadas a la API ni definir el alcance de tokens.
Ejecuta este comando curl, reemplazando YOUR_SITE_ID, YOUR_SITE_TOKEN, y YOUR_WORKER_URL con tus valores reales:
curl -X POST https://api.webflow.com/v2/sites/YOUR_SITE_ID/webhooks \
-H "Authorization: Bearer YOUR_SITE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"triggerType": "ecomm_new_order",
"url": "https://order-confirmation.YOUR-SUBDOMAIN.workers.dev"
}'
Tu ID de sitio aparece en la URL cuando estás en el Diseñador de Webflow (https://webflow.com/design/SITE_ID) o en Configuración del proyecto → General → ID del sitio.
Una respuesta exitosa devuelve un objeto de webhook con un campo id. Guarda este ID. Lo necesitarás si alguna vez quieres actualizar o eliminar el registro del webhook.
Para verificar que el webhook se registró, enumera los webhooks activos de tu sitio:
curl https://api.webflow.com/v2/sites/YOUR_SITE_ID/webhooks \
-H "Authorization: Bearer YOUR_SITE_TOKEN"
Resultado esperado: La respuesta incluye tu webhook con triggerType: "ecomm_new_order" y la URL de tu Worker. Webflow ahora enviará una solicitud POST a esa URL con cada nuevo pedido.
5. Prueba el flujo completo de pedidos
La prueba más fiable es realizar un pedido real en tu sitio publicado utilizando un método de pago de prueba. El modo sandbox de comercio electrónico de Webflow acepta los números de tarjeta de prueba de Stripe (4242 4242 4242 4242, cualquier fecha de caducidad futura, cualquier CVC).
Antes de publicar, desactiva el correo electrónico de confirmación de pedido nativo de Webflow en Configuración del proyecto → Comercio electrónico → Correos electrónicos para evitar enviar dos copias a los clientes.
Realiza un pedido de prueba. En pocos segundos, Webflow activará el webhook. Comprueba dos lugares simultáneamente:
Registros del Worker de Cloudflare: En el panel de control de Cloudflare, navega a Compute → Workers & Pages → tu Worker → Registros. Haz clic en Iniciar flujo de registros antes de realizar el pedido. Deberías ver la solicitud POST entrante registrada en los 5 segundos posteriores a completar la compra.
Tu bandeja de entrada: Revisa la dirección de correo electrónico que usaste al finalizar la compra. La confirmación del pedido debería llegar en un plazo de 10 a 15 segundos.
Si el correo llega pero el formato no es correcto, edita la plantilla en el editor de SendGrid y vuelve a publicarla; no es necesario volver a desplegar el Worker. Los cambios en la plantilla surten efecto de inmediato.
Si no aparece ningún webhook en los registros, la causa más probable es que el webhook no se haya registrado correctamente. Repite el paso 4 y enumera tus webhooks para confirmar.
Resultado esperado: Un correo electrónico de confirmación de pedido con el formato completo llega a la bandeja de entrada de prueba en los 15 segundos posteriores a la realización del pedido, con el nombre del cliente, los nombres de los productos, las cantidades y el total correctos.
¿Qué causa que los correos electrónicos de confirmación de pedido fallen en Webflow?
La mayoría de los fallos se dividen en cuatro categorías: el webhook no se activa, el Worker no recibe la carga útil, SendGrid rechaza la solicitud o los correos se entregan pero terminan en la carpeta de spam. El síntoma en cada caso es visible; la causa, por lo general, no lo es.
Aquí tienes cómo solucionar cada uno.
El webhook se dispara, pero el Worker no muestra ninguna solicitud entrante
Síntoma: El pedido de prueba se completa en Webflow, pero no aparece nada en el flujo de registros del Worker.
Causa: La URL del webhook almacenada en Webflow no coincide con la URL de tu Worker desplegado, o el registro del webhook no se completó correctamente.
Solución: Enumera los webhooks registrados de tu sitio usando el comando curl del Paso 4 y confirma que la URL coincida exactamente con la de tu Worker, incluyendo el https:// prefijo y sin barra diagonal al final. Si la URL es incorrecta, elimina el registro del webhook antiguo usando DELETE https://api.webflow.com/v2/webhooks/{webhook_id} (el endpoint de eliminación solo requiere el ID del webhook, sin sites/ prefijo) y vuelve a registrarlo con la URL correcta.
Además, para confirmar, el triggerType es ecomm_new_order, no form_submissions ni ningún otro tipo de evento.
El worker recibe el webhook, pero SendGrid devuelve un 403
Síntoma: Los registros del Worker muestran la solicitud entrante y el payload de Webflow, pero la respuesta de SendGrid es 403 Forbidden.
Causa: La clave API de SendGrid almacenada en el secreto del Worker no tiene el permiso Mail Send, o la clave fue eliminada/regenerada en SendGrid y el secreto del Worker no se actualizó.
Solución: En SendGrid, ve a Settings → API Keys y verifica que tu clave exista y que Mail Send → Full Access esté habilitado. Si la clave fue regenerada, ejecuta npx wrangler secret put SENDGRID_API_KEY de nuevo con el nuevo valor de la clave y vuelve a desplegar.
Los correos llegan pero terminan en spam
Síntoma: Los registros del Worker muestran una respuesta 202 de SendGrid (envío exitoso), pero el correo termina en la carpeta de spam del destinatario.
Causa: El dominio de envío no está completamente verificado en Sender Authentication de SendGrid, o el dominio de FROM_EMAIL no coincide con el dominio verificado. Un 202 de SendGrid significa que el correo fue aceptado para su entrega, no que llegó a la bandeja de entrada.
Solución: Ve a Settings → Sender Authentication en SendGrid y confirma que tu dominio muestre un estado Verified en verde. Si aparece como no verificado, vuelve a comprobar que los tres registros CNAME se hayan añadido correctamente en tu proveedor de DNS. Usa MXToolbox para verificar que los CNAME se están resolviendo.
Confirma que FROM_EMAIL usa exactamente el dominio que verificaste, no una variante de subdominio que no se incluyó en la autenticación.
Los correos se envían para pedidos de prueba, pero no para pedidos reales de clientes
Síntoma: Cada pedido de prueba activa el correo, pero los pedidos reales de clientes a veces no lo hacen.
Causa: La entrega de webhooks de Webflow tiene un mecanismo de reintento, pero no es indefinido. Si tu Worker devuelve una respuesta que no es 2xx (debido a un error transitorio), Webflow reintenta un número limitado de veces antes de descartar el evento.
Solución: Asegúrate de que tu Worker siempre devuelva una respuesta 2xx, incluso cuando la llamada a SendGrid falle. Registra el fallo internamente y devuelve 200 a Webflow para que no reintente innecesariamente. Para producción, considera registrar los envíos fallidos en un espacio KV de Cloudflare o en un servicio de registro externo para que puedas volver a procesarlos manualmente.
Para volúmenes de pedidos más altos, añade idempotencia almacenando los valores de orderId procesados en un espacio KV de Cloudflare. Antes de llamar a SendGrid, comprueba si ese orderId ya ha sido procesado. Si es así, devuelve 200 sin enviar nada. Esto evita correos duplicados en los reintentos de webhook sin necesidad de infraestructura externa.
Crea mucho más con Webflow E-commerce y SendGrid
Para los equipos que crean flujos de trabajo posventa más complejos (activadores de referidos, asignación de puntos de fidelidad, secuencias de venta adicional), la documentación para desarrolladores de Webflow cubre toda la API de pedidos y la lista completa de eventos de webhook de comercio electrónico.
Si parte de tu equipo necesita gestionar flujos de trabajo de correo electrónico sin tocar el Worker, la integración de SendGrid con Webflow cubre las rutas de automatización sin código que vale la pena revisar en paralelo.
Preguntas frecuentes
¿Esta integración requiere un plan de pago de Webflow?
Sí. El ecomm_new_order evento solo está disponible en los planes de sitio E-commerce de Webflow. Los planes estándar (Starter, CMS, Business) no incluyen funciones nativas de comercio electrónico. Si vendes a través de un carrito de terceros integrado en un sitio de Webflow, el webhook de Webflow no se activará. En ese caso, deberás gestionar el correo de confirmación desde el proveedor del carrito.
¿El webhook de pedidos de Webflow incluye todos los detalles del producto que necesito?
Para la mayoría de los correos de pedidos, sí. La ecomm_new_order carga útil incluye el nombre completo y el correo del cliente, una purchasedItems matriz (nombre del producto, cantidad, precio unitario en centavos y URL de la imagen de la variante por artículo a través de variantImage.url), totales del pedido, dirección de envío y el ID del pedido. Las imágenes de los productos están disponibles directamente en la carga útil. Cada artículo en purchasedItems contiene un variantImage.url campo que puedes pasar directamente a tu plantilla de SendGrid. El código del Worker en el paso 3 lo asigna a lineItems[].image precisamente para este fin.
¿Puedo desactivar el correo de confirmación de pedido nativo de Webflow y enviar confirmaciones solo a través de SendGrid?
Sí, parcialmente. En Configuración del proyecto → Ecommerce → Correos electrónicos, puedes activar o desactivar notificaciones individuales. Desactiva el correo de confirmación de pedido nativo para evitar enviar dos copias a los clientes. Ten en cuenta que el correo de notificación de cumplimiento de Webflow (que se envía al marcar un pedido como cumplido) es un interruptor independiente. Déjalo activado o sustitúyelo por una segunda ruta de SendGrid Worker si también quieres personalizarlo.




