Send email from Supabase with emailr_
Send transactional and auth email from Supabase Edge Functions with emailr_, including a Send Email auth hook for branded signup and magic-link emails.
Supabase Edge Functions run on Deno and can import the emailr npm package directly. This guide covers two jobs: sending app email from an Edge Function, and replacing Supabase Auth's built-in emails with your own through the Send Email hook.
Both run inside your Supabase project, so there's no extra server to deploy.
Set up emailr_ with Supabase
- 01
Create an API key
Create a key under API keys in the dashboard. Keys start with
et_live_and are scoped to one domain workspace. Store it asEMAILR_API_KEYin your secret manager or environment, never in client-side code. - 02
Add and verify your sending domain
In the dashboard, open Domains and add the domain you send from. A subdomain such as
mail.yourcompany.comkeeps transactional reputation separate from your corporate mailbox.Emailr generates the DNS records: a DKIM TXT record on the
emailr._domainkeyselector, an SPF TXT record, and an MX + TXT pair on thesendsubdomain used as the MAIL FROM / Return-Path. A DMARC record is optional but recommended.Emailr's DKIM selector and
sendsubdomain don't collide with other providers' records, so you can add them before cutting over and send from both providers during the migration. A domain can only have one SPF record: if one already exists, merge Emailr'sinclude:into it instead of adding a second record. - 03
Store the key as a secret
Edge Function secrets are exposed through
Deno.env. Set the key with the Supabase CLI.Terminalbashsupabase secrets set EMAILR_API_KEY=et_live_... - 04
Send from an Edge Function
Import the SDK with an
npm:specifier. Call the function from your app withsupabase.functions.invoke('send-email', { body }), or from a Database Webhook when a row is inserted.supabase/functions/send-email/index.tstsimport { Emailr } from 'npm:emailr' const emailr = new Emailr({ apiKey: Deno.env.get('EMAILR_API_KEY')! }) Deno.serve(async (req) => { const { to, name } = await req.json() const result = await emailr.emails.send({ from: 'Acme <hello@mail.acme.com>', to, subject: `Welcome, ${name}`, html: `<p>Hi ${name}, your workspace is ready.</p>`, }) return Response.json({ id: result.message_id }) }) - 05
Replace Auth emails with the Send Email hook
In the dashboard, open Authentication → Hooks, add a Send Email hook of type HTTPS pointing at your function, and copy the generated secret into
SEND_EMAIL_HOOK_SECRET. Supabase signs hook requests with Standard Webhooks, and the payload contains the user plusemail_datawith the token hash and action type.Deploy this function with
supabase functions deploy send-email-hook --no-verify-jwt, because the hook authenticates with its own signature rather than a user JWT.supabase/functions/send-email-hook/index.tstsimport { Webhook } from 'https://esm.sh/standardwebhooks@1.0.0' import { Emailr } from 'npm:emailr' const emailr = new Emailr({ apiKey: Deno.env.get('EMAILR_API_KEY')! }) const hookSecret = Deno.env.get('SEND_EMAIL_HOOK_SECRET')!.replace('v1,whsec_', '') Deno.serve(async (req) => { const payload = await req.text() const headers = Object.fromEntries(req.headers) const { user, email_data } = new Webhook(hookSecret).verify(payload, headers) as { user: { email: string } email_data: { token_hash: string; redirect_to: string; email_action_type: string } } const link = `${Deno.env.get('SUPABASE_URL')}/auth/v1/verify?token=${email_data.token_hash}` + `&type=${email_data.email_action_type}&redirect_to=${email_data.redirect_to}` await emailr.emails.send({ from: 'Acme <auth@mail.acme.com>', to: user.email, subject: 'Confirm your email', html: `<p><a href="${link}">Confirm your email address</a></p>`, }) return Response.json({}) })
Tips
- Branch on
email_action_type(signup, magiclink, recovery, invite, email_change) to send a different subject and template for each. - Returning a non-2xx status from the hook makes Supabase Auth report the failure to the user, so let SDK errors propagate.
SUPABASE_URLis available in Edge Functions by default.
Frequently asked questions
Can I use emailr_ for Supabase Auth emails?
Yes. Configure a Send Email auth hook that points at an Edge Function, verify the Standard Webhooks signature, and send the confirmation or magic link through emailr_.
Does the emailr_ SDK work in Supabase Edge Functions?
Yes. Import it with the npm:emailr specifier. It uses fetch and runs on Deno without extra configuration.
Do I still need Supabase's SMTP settings?
No. With the Send Email hook enabled, Supabase Auth calls your function instead of sending email itself.
How do I send email when a database row changes?
Create a Database Webhook on the table that calls your Edge Function, and send from the function with the row data in the request body.
Keep going
Documentation
Related guides
- Send email from Next.jsSend transactional email from Next.js App Router route handlers and server actions with the emailr_ SDK, and verify delivery webhooks safely.
- Send email from Vercel FunctionsSend transactional email from Vercel Functions with emailr_, manage keys with Vercel environment variables and schedule digest emails with Vercel Cron.
- Send email from Cloudflare WorkersSend transactional email from Cloudflare Workers with the fetch-based emailr_ SDK, store keys as Worker secrets and verify webhooks with Web Crypto.
Start sending in minutes
Create a free account, verify your domain and send your first email. No credit card required.