Skip to content

Guide

Send email from Supabase: Auth, your app, sign-up follow-ups

Supabase's built-in email is for testing. Set up your own SMTP for Auth, send your app's emails from an Edge Function, and follow up on every sign-up.

The short answer

Supabase Auth sends the emails sign-in needs, and the service it uses out of the box is for trying things out. Sending email from a Supabase project is really three jobs: Auth's own emails, which need your own SMTP service; your app's emails, like a receipt or a notification, which you send from an Edge Function or your server; and the follow-up after somebody signs up, which Supabase has no hook for.

Auth emails: use your own SMTP

As of 28 October 2026, Supabase's docs say the built-in service is not for production. Without your own SMTP server it delivers only to addresses on your project's team, so anyone else gets "Email address not authorized". It also stops at 2 messages an hour, a limit Supabase says can change, and comes with no uptime guarantee.

To email everyone, pick a provider that supports SMTP (the docs name Resend, AWS SES, Postmark, Twilio SendGrid, ZeptoMail and Brevo), take its host, port, user and password, choose a From address, and enter them under Authentication in the dashboard. Auth then sends to everyone, at a default of 30 messages an hour that you can raise on the Rate Limits page. Supabase suggests separate sending domains and From addresses for Auth and for marketing email.

Your app's emails: an Edge Function

For anything else you trigger, the usual route is an Edge Function that calls your email provider. Supabase's example uses Resend: keep the provider's key with supabase secrets set, read it in the function with Deno.env.get, and deploy with supabase functions deploy. Call the function from your app, or from a Database Webhook so that a new row sends one.

Sign-up follow-ups: the welcome and the nudges

Auth's hooks are Before User Created, Custom Access Token, Send SMS and Send Email, plus two for Teams and Enterprise, so none runs after a user is created. You catch the sign-up yourself, in your own sign-up code or with a Database Webhook, which fires after a row changes and sends through pg_net without blocking your database.

Kicklace turns that sign-up into the emails that follow it, a welcome and a nudge for people who stall, written in your voice. Supabase is not one of its built-in connections (Clerk and Kinde are), so you post the sign-up yourself. With a Database Webhook on a table you own, such as profiles, holding the person's email, the whole function is this:

// supabase/functions/kicklace-signup/index.ts
import { withSupabase } from "npm:@supabase/server@1";

export default {
  fetch: withSupabase({ auth: "secret" }, async (req) => {
    const { record } = await req.json();
    const res = await fetch("https://www.kicklace.com/api/v1/events", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        authorization: `Bearer ${Deno.env.get("KICKLACE_SECRET_KEY")}`,
      },
      body: JSON.stringify({
        type: "signup",
        email: record.email,
        idempotency_key: `signup:${record.id}`,
      }),
    });
    return new Response(null, { status: res.ok ? 200 : 502 });
  }),
};
  1. Make a secret key in Kicklace under Connections → Your website → Developers, and store it with supabase secrets set KICKLACE_SECRET_KEY=sk_live_….
  2. Add [functions.kicklace-signup] with verify_jwt = false to supabase/config.toml, since withSupabase checks the secret key the webhook sends, and run supabase functions deploy kicklace-signup.
  3. In the dashboard, make a Database Webhook on profiles for inserts, choose Supabase Edge Functions and this function, and add the secret key under HTTP Headers.
  4. On the Lifecycle map, open the email at Signed up, read it, change what you like and switch it on. Kicklace shows who would have got it over the last 30 days first.

The idempotency_key makes a repeat land once. With your own sign-up code instead of a webhook, one line does it, and Supabase: send a welcome email has that version and the email itself. Try it on your own site in the demo, with no sign-up.

Kicklace does not send Supabase's Auth emails. The confirmation link and the password reset stay with Supabase and your SMTP provider.

FAQ

Why is Supabase not sending my email?

Most often the built-in service is in the way: it only delivers to your team's addresses and stops at 2 messages an hour. Set your own SMTP server under Authentication and the limit becomes 30 an hour by default.

Can I send email from Supabase without SMTP?

Your own emails, yes, since an Edge Function can call a provider's API directly. Auth's emails need SMTP, or the Send Email hook, which lets your own code send them through a provider you choose.

What does it cost?

Kicklace is free up to 1,000 contacts, sending from its own address with your name on it and a small “Sent with Kicklace” line under each email. Your own domain is part of Starter, $25 a month. The details are on pricing.

Free up to 1,000 contacts.

Join the journey

We're building Kicklace so you can get back to building your own product. We'll email you when there's something new worth showing.