Emails transaccionales con Resend y Supabase

Resumen

Conectar Resend con Next.js y Supabase te permite enviar correos transaccionales cada vez que un usuario recibe un like o comentario en su contenido. Es el mismo patrón que usan Instagram o X: notificaciones puntuales disparadas por acciones reales, no campañas de marketing.

La lógica base es simple: detectar la interacción, obtener el correo del dueño del post, construir la notificación y enviarla desde el servidor.

¿Qué variables de entorno necesitas configurar?

Antes de tocar código, hay dos llaves que debes guardar en tu archivo de variables de entorno [01:00].

  • API Key de Resend: la generas desde el panel de Resend en la sección API Keys, le pones un nombre identificable (por ejemplo, SuplatziGram) y le das full access.
  • Service Role Key de Supabase: la encuentras en Project Settings dentro de API Keys, en el segundo tab. Debes activarla para copiar el valor completo.

La diferencia entre ambas claves de Supabase es clave: la anon key expuesta sirve para el cliente, mientras que la service role key habilita operaciones desde el lado del servidor, como leer datos protegidos por políticas de seguridad.

¿Qué es la Service Role Key de Supabase? Es una llave con permisos elevados que solo debe usarse en código del servidor. Permite saltarse las políticas RLS para ejecutar acciones administrativas, como obtener el email del dueño de un post.

¿Cómo se instala y se conecta Resend en el proyecto?

La instalación se hace con un solo comando: npm install resend [02:10]. Puedes validar que quedó instalada revisando tu package.json; con la versión 6 o superior, todo el flujo del curso funciona sin problemas.

Luego viene la parte estructural: como necesitas ejecutar el envío desde el servidor para acceder a la base de datos y disparar el email, aprovechas las API Routes de Next.js. Creas una carpeta api y dentro un endpoint llamado sendCommentEmail con su archivo route.ts.

¿Qué hace el endpoint sendCommentEmail?

Es una función HTTP en método POST que recibe un objeto con cinco campos:

  1. ID del dueño del post.
  2. Username del dueño.
  3. Username de quien comenta.
  4. Cuerpo del comentario.
  5. Caption del post.

El endpoint valida que cada campo exista; si falta alguno, responde con un error. Luego usa el cliente con service role para obtener el email del titular y dispara el correo.

¿Cómo se construye el envío con resend.emails.send?

A partir de la línea 29 del archivo aparece la función resend.emails.send, que recibe un objeto con todos los datos del correo [04:30]:

  • from: identifica al remitente, en este caso SuplatziGram desde noresponder@suplatzigram.site.
  • to: el email del dueño del post, recuperado desde Supabase.
  • subject: incluye un emoji y el username de quien comentó.
  • html: una plantilla con HTML inline, estilo old school, que muestra el comentario en formato quote y un substring del caption original.

Todo el bloque está envuelto en manejo de errores: si Resend falla o si algo se rompe antes, la API responde con estatus 500 y registra el error en consola.

¿Cómo se separa el código de cliente y servidor en Supabase?

El cambio más importante ocurre en client.ts, el archivo que conecta con la librería supabase-js. Antes solo tenía seis líneas; ahora, a partir de la línea ocho, se valida la nueva service role key y se exporta como serviceKey para uso exclusivo en el servidor.

La convención es clara: todo lo que se ejecuta del lado del cliente sigue usando supabase, mientras que las operaciones del servidor consumen el cliente con permisos elevados. Puedes tenerlos en archivos separados (client.ts y server.ts) o juntos, eso va a gusto.

¿Por qué separar cliente y servidor en Supabase? Porque la service role key nunca debe exponerse al navegador. Si se filtra, cualquiera puede leer y modificar tu base de datos saltándose las políticas de seguridad.

¿Cómo se dispara el email desde el front-end?

En page.tsx, la página principal de la app, se ajusta la lógica para que al guardar un nuevo comentario también se lleve el perfil de quien comenta. Si el username de quien comenta es distinto al dueño del post, se ejecuta un fetch en método POST hacia /api/sendCommentEmail [07:20].

El body envía toda la información que el endpoint espera. Si el endpoint responde con error, se imprime Error enviando email en consola; si todo sale bien, Resend dispara el correo al destinatario.

¿Cómo se ve el flujo funcionando en el navegador?

Al publicar un comentario en un post creado por una cuenta con email real, el correo llega casi al instante. El asunto muestra el username de quien comentó, el cuerpo despliega el mensaje en formato quote y debajo aparece un fragmento del caption original.

Lo importante: el remitente es noresponder@suplatzigram.site, no hay rastros de Supabase en el correo, porque Resend ya está configurado como proveedor de envío con dominio propio.

¿Cómo verificar que el email se envió correctamente?

Entra al panel de Resend, ve a la sección Emails y revisa el último registro [09:40]. Verás la hora exacta de envío y entrega, junto con el contenido completo. En el ejemplo de la clase, el correo fue enviado y entregado a las 4:18, lo que confirma que toda la cadena (front-end, API Route, Supabase y Resend) está conectada.

Con esto tienes el primer paso hacia un sistema de notificaciones completo. Los siguientes pasos lógicos serían mejorar las plantillas HTML, automatizar el disparo desde el servidor sin depender del front-end y agregar más eventos como likes o follows. ¿Cómo lo harías tú? Cuéntame en los comentarios y comparte tus plantillas si ya las personalizaste.