Guía Supabase
Una fila nueva en Supabase,
sale un email y un WhatsApp.
Un database webhook llama a una Edge Function en cada insert, la función hace una llamada API y el mensaje de bienvenida o de pedido sale de tu buzón, de tu número de WhatsApp o de tu móvil Android. Gratis, con el código y un prompt para tu editor de IA.
¿Con prisa? Resume este artículo con una IA
La respuesta corta
¿Cómo enviar email, SMS y WhatsApp desde Supabase?
Crea un database webhook en tu tabla (profiles, orders) que llame a una Edge Function de Supabase en cada INSERT. La función lee la fila nueva y hace una petición POST /message a Unlimited Messaging, que envía el email desde tu buzón, el WhatsApp desde tu número y el SMS desde tu móvil Android. Los database webhooks usan pg_net, así que el insert nunca espera al mensaje.
Supabase no tiene una API para los mensajes que envía tu aplicación. Su servicio de email integrado sirve para los emails de Auth: envía 2 mensajes por hora, solo a direcciones del equipo del proyecto, y Supabase indica que no está pensado para producción. Un email de bienvenida, una confirmación de pedido o un WhatsApp al cliente te toca enviarlos a ti.
Una Edge Function es el lugar adecuado: se ejecuta en el servidor, lee los secretos con Deno.env.get y el plan Free de Supabase incluye 500.000 invocaciones. Lo habitual es un proveedor por canal, una API de email, Twilio para SMS, la Cloud API de Meta para WhatsApp: tres claves, tres facturas. Aquí una sola petición cubre los tres canales, y el plan Free de Unlimited Messaging no cobra por mensaje.
Esta guía cubre los mensajes que envía tu aplicación. Los emails de Auth (confirmación de registro, magic link, restablecer contraseña) y el OTP por teléfono siguen en los ajustes de Supabase Auth, donde conectas un servidor SMTP o un proveedor de SMS.
Lee también: email y WhatsApp en una sola petición API, y la API de SMS gratis que envía desde tu propio móvil.

Paso a paso
¿Cómo se monta, paso a paso?
Cinco pasos, unos 15 minutos. Necesitas un proyecto de Supabase, la CLI de Supabase y una cuenta gratis de Unlimited Messaging.
Conecta tus canales y crea una clave API
En la app de Unlimited Messaging, vincula tu número de WhatsApp con un código QR, conecta tu buzón por IMAP/SMTP (sirve una contraseña de aplicación de Gmail) y, para SMS, inicia sesión en la app Android gratuita en un móvil con SIM. Conecta solo los canales que uses y crea una clave API.
supabase/functions/.env.env# supabase/functions/.env (gitignored, local only) # Created at app.unlimitedmessaging.app > API keys UM_API_KEY=um_live_xxxx # Any long random string, shared with the database webhook WEBHOOK_SECRET=change-me-to-a-long-random-stringCrea la función y guarda los secretos
Crea la función con la CLI y sube los dos secretos a tu proyecto. Solo viven en el entorno de la función: nunca pongas la clave API en una variable VITE_ o NEXT_PUBLIC_, ni en ningún código del frontend.
TerminalSupabase CLIsupabase functions new notify-signup # Push the secrets to your project (never to the frontend) supabase secrets set --env-file supabase/functions/.env supabase secrets listEscribe la función
La función comprueba el secreto compartido, lee la fila insertada, envía el email siempre y el WhatsApp solo si la fila tiene número. priority: transactional pone el mensaje por delante de cualquier envío masivo que espere en tu cola.
notify-signup/index.tsDeno / TypeScript// supabase/functions/notify-signup/index.ts type Profile = { id: string; email: string; phone: string | null; full_name: string | null }; type WebhookPayload = { type: 'INSERT' | 'UPDATE' | 'DELETE'; table: string; schema: string; record: Profile; old_record: Profile | null; }; Deno.serve(async (req) => { // The database webhook sends this header; nobody else knows it if (req.headers.get('x-webhook-secret') !== Deno.env.get('WEBHOOK_SECRET')) { return new Response('Unauthorized', { status: 401 }); } const { record } = (await req.json()) as WebhookPayload; const name = record.full_name ?? 'there'; // Email always, WhatsApp when the row has a phone (E.164: +33612345678). // Use { channel: 'SMS' } instead for people who are not on WhatsApp. const channels: Array<{ channel: 'EMAIL' | 'WHATSAPP' | 'SMS' }> = [{ channel: 'EMAIL' }]; if (record.phone) channels.push({ channel: 'WHATSAPP' }); const res = await fetch('https://api.unlimitedmessaging.app/message', { method: 'POST', headers: { Authorization: `Bearer ${Deno.env.get('UM_API_KEY')}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ to: { email: record.email, phone: record.phone ?? undefined }, channels, subject: 'Welcome aboard', text: `Hi ${name}, your account is ready. Reply to this message if you need anything.`, priority: 'transactional', }), }); if (!res.ok) console.error('Unlimited Messaging', res.status, await res.text()); return new Response(null, { status: res.ok ? 200 : 502 }); });Despliégala, protegida por tu propio secreto
Un database webhook no envía un JWT de usuario: desactiva la verificación de la plataforma solo para esta función (--no-verify-jwt, o verify_jwt = false en config.toml). La cabecera x-webhook-secret que comprueba la función deja fuera a los desconocidos.
TerminalSupabase CLI# A database webhook sends no user JWT: turn the platform check off # for this function only, the x-webhook-secret header protects it supabase functions deploy notify-signup --no-verify-jwt # Or keep it in supabase/config.toml: # [functions.notify-signup] # verify_jwt = falseCrea el database webhook
En el dashboard, Database > Webhooks: elige la tabla (aquí profiles), el evento Insert, el tipo Supabase Edge Functions y la función notify-signup, y añade una cabecera x-webhook-secret con el mismo valor. Inserta una fila de prueba: este es el cuerpo que recibe la función.
Cuerpo del POSTWebhook payload{ "type": "INSERT", "table": "profiles", "schema": "public", "record": { "id": "8f1c2d3e-0000-4000-8000-000000000000", "email": "[email protected]", "phone": "+33612345678", "full_name": "Lea" }, "old_record": null }
Vibe coding
¿Programas con Lovable, Cursor o Claude Code? Pega este prompt
El prompt le da a tu editor de IA el patrón exacto: una Edge Function, los secretos en Supabase, una llamada REST. Te pregunta antes de enviar nada de verdad.
Añade notificaciones transaccionales a este proyecto de Supabase con Unlimited Messaging (email, WhatsApp y SMS enviados desde mis propias cuentas).
1. Crea una Edge Function de Supabase llamada notify-signup. Lee UM_API_KEY y WEBHOOK_SECRET con Deno.env.get. Nunca pongas la clave en el código del frontend ni en una variable VITE_ / NEXT_PUBLIC_.
2. La función recibe el payload de un database webhook de Supabase { type, table, schema, record, old_record }. Devuelve 401 si la cabecera x-webhook-secret no es igual a WEBHOOK_SECRET.
3. Envía un POST https://api.unlimitedmessaging.app/message con la cabecera Authorization: Bearer UM_API_KEY y el JSON { to: { email, phone }, channels: [{ channel: 'EMAIL' }, { channel: 'WHATSAPP' }], subject, text, priority: 'transactional' }. Añade WHATSAPP (o SMS) solo si la fila tiene un número en formato E.164.
4. Dame los comandos: supabase secrets set, supabase functions deploy notify-signup --no-verify-jwt, y cómo crear el database webhook en el INSERT de mi tabla con la cabecera x-webhook-secret.
5. Referencia de la API: https://docs.unlimitedmessaging.app. Creo la clave API en https://app.unlimitedmessaging.app.
Pregúntame qué tabla y qué texto de mensaje usar antes de escribir el código.Las opciones
¿Qué opción para enviar mensajes desde Supabase?
Cuatro formas de enviar una notificación cuando llega una fila a tu base de datos, del servicio integrado a una sola API para todos los canales.
| Email integrado de SupabaseSolo emails de Auth | Resend desde una funciónAPI de email | Twilio desde una funciónAPI de SMS y WhatsApp | Unlimited MessagingEmail, WhatsApp y SMS | |
|---|---|---|---|---|
| Canales | Solo emails de Auth | SMS y WhatsApp, cobrados por mensaje | Email, WhatsApp y SMS en una petición | |
| Gratis | 2 emails por hora, solo direcciones del equipo | 3.000 emails al mes, 100 al día | Prueba: hasta 5 números verificados | Plan Free sin coste por mensaje |
| Remitente | La dirección de Supabase | Tu dominio verificado | Un número de Twilio o un remitente de WhatsApp registrado | Tu propio buzón, tu número de WhatsApp y tu móvil |
| Mensajes de WhatsApp | No | No | Plantillas aprobadas por Meta para iniciar una conversación | Texto libre desde tu número vinculado |
| Configuración | Ninguna | Registros DNS de tu dominio | Cuenta, número, registro del remitente de WhatsApp | Código QR, acceso IMAP/SMTP, app Android |
| Ideal para | Probar los flujos de Auth | Email en gran volumen | SMS en volumen, WhatsApp oficial | Mensajes de una app uno a uno, gratis mientras creces |
Comprobado el 9 de noviembre de 2026 en supabase.com, resend.com/pricing y la documentación de prueba de Twilio (enlaces en las fuentes). Los planes gratis cambian: sigue los enlaces antes de construir sobre uno.
La letra pequeña
¿Cuáles son los límites?
Gratis quita la factura por mensaje. No quita las reglas de WhatsApp, de tu móvil ni de tu buzón.
WhatsApp es no oficial, y el spam hace que bloqueen números
Tu número se vincula como un dispositivo, fuera de la plataforma Business de Meta. Escribir a clientes registrados que esperan el mensaje es de bajo riesgo; los envíos masivos a desconocidos pueden hacer que bloqueen el número. Usa WhatsApp para mensajes transaccionales.
El SMS necesita un móvil Android encendido
Los SMS salen de la SIM del móvil, con tu tarifa. Android pide confirmación a partir de 30 SMS en 30 minutos, así que la app espacia los envíos a unos 30 cada 30 minutos: bien para registros y pedidos, no para un envío masivo el día del lanzamiento.
El email sigue los límites de tu buzón
Los emails salen de tu buzón por SMTP, así que se aplica su tope diario: 500 al día en una cuenta de Gmail. Para newsletters a miles de personas, usa un servicio de email masivo.
Los mensajes del plan Free llevan una firma
En el plan Free, los mensajes terminan con una línea corta "Sent with UnlimitedMessaging.app", y los archivos multimedia y los webhooks son de pago. Medium y Max quitan la línea.
El insert no espera al mensaje
pg_net envía la petición de forma asíncrona: una función que falla nunca deshace el insert. Registra la respuesta de la API en la función y vigila sus logs.
La clave se queda en el servidor
Cualquiera que abra tu bundle del frontend puede reutilizar una clave que esté ahí. La clave va en los secretos de la Edge Function, y el secreto del webhook impide que desconocidos llamen a tu función.
FAQ
Preguntas sobre enviar mensajes desde Supabase
Fuentes
Fuentes y referencias
Para verificar por ti mismo la información de este artículo:
- Database WebhooksSupabase Docs
- Managing secrets (environment variables) for Edge FunctionsSupabase Docs
- Function configuration (verify_jwt)Supabase Docs
- Send emails with custom SMTP (límite integrado: 2 mensajes por hora)Supabase Docs
- Pricing (500.000 invocaciones de Edge Functions en Free)Supabase
- Pricing (Free: 3.000 emails al mes, 100 al día)Resend
- How to use your free trial account (Messaging)Twilio Docs
- Message templatesMeta for Developers
- Límites de envío y recepción (500 emails al día)Ayuda de Gmail
- SmsUsageMonitor (umbral de 30 SMS en 30 minutos)Android Open Source Project
- Referencia de la API: POST /messageUnlimited Messaging Docs

Escrito por
Ilian · Ingeniero de software senior
Ingeniero de software senior, funda y dirige varias empresas tecnológicas. Diseña productos en torno a las API de mensajería, la automatización y la integración de la IA, y comparte aquí lo que aprende construyendo.
Envía hoy tu primera notificación desde Supabase.
Crea una cuenta gratis, conecta un buzón o un número de WhatsApp y pega la función. Sin tarjeta, sin coste por mensaje.