Torna al Blog
supabase
email
transazionale
lifecycle-messaging
tutorial

Come inviare email da Supabase (il pezzo mancante)

13 aprile 20268 min readScritto da Minimo Team
Sviluppatore che collega un database Supabase a un workflow di invio email

Supabase è uno stack incredibile. Auth, Postgres, storage, edge function, realtime, vector: tutto in un posto. Puoi spedire un prodotto vero in un weekend.

Poi ti serve inviare un'email. E scopri il pezzo mancante.

Supabase ti permette di configurare l'email (SMTP per l'auth) ma deliberatamente non manda email marketing o lifecycle. Il layer auth.email è limitato a 2 email all'ora sul piano free, e anche su Pro ha un cap duro e copre solo eventi di auth. Nel momento in cui ti serve una welcome sequence, un reminder di trial in scadenza, un nudge di pagamento fallito, o una campagna di re-engagement, sei per conto tuo.

Questo post parla di cosa succede dopo. Attraverso i tre workaround più comuni che vedo in giro per chi costruisce su Supabase, spiego dove ognuno si rompe, e mostro come appare un approccio DB-native pulito.


Perché Supabase non include un layer email completo

Illustration for the inviare email da supabase article

Il team di Supabase l'ha detto pubblicamente: vogliono essere il miglior backend, non un tool di marketing. È la scelta giusta per loro: deliverability, compliance, bounce, reputation, flussi di unsubscribe, rendering template, A/B test, segmentazione: è un prodotto intero, non una feature.

L'effetto collaterale è che ogni SaaS su Supabase deve attaccarci l'email separatamente. E il modo in cui la gente lo fa oggi va da "funziona ma costa" a "funziona finché non si rompe in silenzio."

Il primo limite che sbatti

L'auth SMTP di Supabase è rate-limited:

PianoEmail auth / oraCopre
Free2Signup, reset password, magic link
Pro~30Solo eventi di auth
Custom SMTPIllimitato*Quello che permette il tuo provider

La seconda riga è dove la maggior parte dei solo-founder sbatte il muro. Lanci su Reddit, 400 persone fanno signup in un'ora, e 370 di loro non ricevono mai il link di welcome perché hai sfondato il cap. Pensi che il problema sia "Supabase è lento oggi." Non lo è. Ti serviva un tool diverso ieri.


Workaround 1: Resend + webhook custom

Lo stack DIY più popolare. Compri Resend (o Postmark, SendGrid), scrivi una edge function che ascolta i cambi al DB o le chiamate API, e chiami l'API dell'email provider da lì.

Com'è fatto

// supabase/functions/send-welcome/index.ts
import { Resend } from "npm:resend"

const resend = new Resend(Deno.env.get("RESEND_API_KEY"))

Deno.serve(async (req) => {
  const { record } = await req.json()

  await resend.emails.send({
    from: "hello@yourapp.com",
    to: record.email,
    subject: "Benvenuto su YourApp",
    html: `<p>Ciao ${record.first_name}, benvenuto!</p>`,
  })

  return new Response("ok")
})

Più un trigger sul database o un webhook che attiva la function quando users riceve una nuova riga.

Dove si rompe

Tre posti, in ordine di quando ti mordono:

  1. L'HTML vive nel codice. Cambiare una virgola nell'email di welcome richiede un cambio al codice, una PR, un redeploy. La tua cofounder non tecnica non può toccarlo. Il designer non può vederlo in anteprima. Il tuo agente Claude Code può editarlo, ma ora hai un diff di 4 righe a ogni tweak di copy che infiorisce il tuo git log.
  2. La seconda email ti uccide. La welcome è facile. Ora ti serve: trial in scadenza a T-3 giorni, retry di pagamento fallito, nudge di feature, digest settimanale. Ognuno è una nuova edge function, un nuovo trigger, nuovo stato da tracciare (l'abbiamo già mandata?), nuova logica di idempotenza. Finisci con 12 edge function e un Google Sheet che traccia quale utente ha ricevuto quale email. È così che spariscono 3 mesi di runway.
  3. Non hai una vista lato utente. Non hai idea di quali utenti abbiano ricevuto quali messaggi, quali siano rimbalzati, quali abbiano cliccato. Scopri i problemi quando gli utenti te lo dicono su Discord. Resend ha una dashboard, ma è raggruppata per batch di invio, non per utente: quindi "questo utente ha ricevuto l'onboarding?" è una domanda a cui non puoi rispondere senza un foglio Excel.

Questo approccio è ok per il solo transazionale (reset password, ricevute). Crolla nel momento in cui ti serve lifecycle.


Workaround 2: Customer.io con reverse ETL

Illustration for the inviare email da supabase article

La versione adulta. Tieni Customer.io (o Braze, o Iterable) come piattaforma di messaggistica e mandi i dati Supabase fuori tramite un tool di reverse ETL come Hightouch o Census.

Com'è fatto

Supabase (Postgres)  →  Sync Hightouch ogni 15 min  →  Customer.io
                                                              ↓
                                                      Email, push, in-app

Definisci modelli in Hightouch (users_active, trial_expiring), schedu i sync, Customer.io riceve gli utenti come oggetti "people", e costruisci i flow nella loro UI.

Dove si rompe

Funziona davvero. Il problema è costo e latenza.

Costo: Customer.io parte da circa $100/mese con un limite basso. Il free tier di Hightouch è minuscolo, poi salta a $450+/mese. Parli di ~$600/mese prima di avere 100 utenti paganti. Per un SaaS bootstrapped è brutale.

Latenza: I sync Hightouch più economici girano ogni 15 minuti. Significa che un utente fa signup alle 10:00, il sync parte alle 10:15, Customer.io valuta l'audience alle 10:15:30, il messaggio di "welcome" parte alle 10:16. Sedici minuti dopo il signup sono tempo morto: l'utente si è già attivato o è già uscito. Puoi pagare di più per sync più veloci, ma ora sei a $800+/mese e hai ancora un sync invece di un vero trigger.

Duplicazione dei dati: I dati dei tuoi utenti vivono in due posti. Ogni cambio di schema in Supabase significa aggiornare un modello Hightouch. Ogni richiesta di privacy significa cancellare da entrambi i sistemi. Ogni sessione di debug parte con "è un problema Supabase o Customer.io?"

Questo stack funziona benissimo a $2M di ARR. È sbagliato per SaaS vibe-coded tra $0 e $100k di ARR.


Workaround 3: Mailchimp + import CSV

Non farlo. Per favore non farlo.

Lo includo perché lo vedo ogni settimana. Qualcuno esporta gli utenti da Supabase in un CSV, li carica su Mailchimp, manda un broadcast, e lo chiama "marketing automation."

Non lo è. È una mailing list del 2010. Non c'è nessun trigger, nessuna personalizzazione oltre al nome, nessun collegamento agli eventi del database, e stai violando GDPR nel momento in cui un utente che ha cancellato il proprio account nella tua app riceve ancora il tuo aggiornamento mensile perché ti sei dimenticato di riesportare.

Se lo stai facendo, otterresti risultati migliori mandando da Gmail a mano. Almeno te ne accorgeresti.


Com'è fatto davvero il pezzo mancante

Il filo conduttore di tutti e tre i workaround è che allontanano i dati dal database. Sincronizzano, copiano, esportano. E ogni copia è un nuovo posto dove le cose possono marcire.

L'approccio che funziona per i SaaS su Supabase è l'opposto: il layer email legge il database direttamente, ascolta i cambiamenti in real-time, e attiva i messaggi senza mai spostare i dati fuori.

Tre cose che devono essere vere

  1. Trigger real-time, non polling. Quando una riga in users cambia, il layer email lo sa entro millisecondi: non 15 minuti dopo. Supabase ha già il realtime. Usalo.
  2. Il contenuto vive fuori dal codice. L'email di welcome ha un ID stabile (welcome_v1). Il tuo backend chiama "manda welcome_v1 a questo utente." Il contenuto è un template in un editor visuale, editabile senza toccare il codice. I cambi di copy non hanno bisogno di deploy.
  3. Gli utenti sono utenti, non "people". La piattaforma email ti mostra i tuoi utenti Supabase reali con le loro colonne vere (trial_ends_at, onboarding_step, plan). Non una copia ombra di reverse-ETL con 15 minuti di ritardo.

Lo stack che fa questo

Minimo è costruito attorno a questo approccio. Si collega in read-only al tuo progetto Supabase, ascolta i cambiamenti realtime, memorizza lo stato dei messaggi (delivered, opened, bounced, ecc.) nel proprio DB: e non ti chiede mai di sincronizzare gli utenti fuori.

// Il tuo backend, dopo il signup
await minimo.send({
  template: "welcome_v1",       // UID stabile
  to: { user_id: newUser.id },  // Minimo risolve da Supabase
})

Fine. Nessun webhook da mantenere. Nessun conto Hightouch. Nessun import CSV. Editi l'email di welcome nell'editor visuale di Minimo e il prossimo invio usa la nuova versione: nessun cambio al codice, nessun deploy.

E quando sei pronto ad aggiungere un reminder di trial in scadenza, non scrivi una nuova edge function. Apri l'automation builder, trascini un nodo trigger ("quando trial_ends_at è tra 3 giorni"), lo colleghi a un delay, lo colleghi a un'azione "manda template." Dieci minuti di click, stessa fonte di verità, stessi oggetti utente.


In sintesi

Supabase lascia deliberatamente fuori l'email, e per loro è corretto. Ma il gap lascia ogni SaaS su Supabase con una scelta tra uno stack DIY che si rompe a scala, uno stack enterprise che costa $600+/mese prima ancora di avere fatturato, o un workflow CSV che nel 2026 non dovrebbe esistere.

Il pezzo mancante è un layer di messaggistica che tratta il tuo database come fonte di verità invece che come qualcosa da copiare. È quello che stiamo costruendo.

Se sei nel mezzo del loop Resend + edge function adesso e lo senti mangiarti i weekend: non devi continuare così. Apri un account Minimo gratuito e collega il tuo progetto Supabase. Ci vogliono circa cinque minuti, e la prima email di welcome che mandi non avrà bisogno di un redeploy.


Per approfondire

Prova Minimo

Il messaggio multicanale che vive nel tuo database.

Connetti Supabase o Postgres. Il tuo agente AI parte già collegato.

14 giorni · nessuna carta richiesta