Custom Auth Emails with React Email and Resend
Use the send email hook to send custom auth emails with React Email and Resend in Supabase Edge Functions.
Prefer to jump straight to the code? Check out the example on GitHub.
To get the most out of this guide, you’ll need to:
Make sure you have the latest version of the Supabase CLI installed.
Create a new function locally:
_10supabase functions new send-email
Paste the following code into the index.ts
file:
supabase/functions/send-email/index.ts
_78import React from 'npm:react@18.3.1'
_78import { Webhook } from 'https://esm.sh/standardwebhooks@1.0.0'
_78import { Resend } from 'npm:resend@4.0.0'
_78import { renderAsync } from 'npm:@react-email/components@0.0.22'
_78import { MagicLinkEmail } from './_templates/magic-link.tsx'
_78const resend = new Resend(Deno.env.get('RESEND_API_KEY') as string)
_78const hookSecret = Deno.env.get('SEND_EMAIL_HOOK_SECRET') as string
_78Deno.serve(async (req) => {
_78 if (req.method !== 'POST') {
_78 return new Response('not allowed', { status: 400 })
_78 const payload = await req.text()
_78 const headers = Object.fromEntries(req.headers)
_78 const wh = new Webhook(hookSecret)
_78 email_data: { token, token_hash, redirect_to, email_action_type },
_78 } = wh.verify(payload, headers) as {
_78 email_action_type: string
_78 token_hash_new: string
_78 const html = await renderAsync(
_78 React.createElement(MagicLinkEmail, {
_78 supabase_url: Deno.env.get('SUPABASE_URL') ?? '',
_78 const { error } = await resend.emails.send({
_78 from: 'welcome <onboarding@resend.dev>',
_78 subject: 'Supa Custom MagicLink!',
_78 http_code: error.code,
_78 message: error.message,
_78 headers: { 'Content-Type': 'application/json' },
_78 const responseHeaders = new Headers()
_78 responseHeaders.set('Content-Type', 'application/json')
_78 return new Response(JSON.stringify({}), {
_78 headers: responseHeaders,
Create a new folder _templates
and create a new file magic-link.tsx
with the following code:
supabase/functions/send-email/_templates/magic-link.tsx
_130} from 'npm:@react-email/components@0.0.22'
_130import * as React from 'npm:react@18.3.1'
_130interface MagicLinkEmailProps {
_130 supabase_url: string
_130 email_action_type: string
_130export const MagicLinkEmail = ({
_130}: MagicLinkEmailProps) => (
_130 <Preview>Log in with this magic link</Preview>
_130 <Container style={container}>
_130 <Heading style={h1}>Login</Heading>
_130 href={`${supabase_url}/auth/v1/verify?token=${token_hash}&type=${email_action_type}&redirect_to=${redirect_to}`}
_130 marginBottom: '16px',
_130 Click here to log in with this magic link
_130 <Text style={{ ...text, marginBottom: '14px' }}>
_130 Or, copy and paste this temporary login code:
_130 <code style={code}>{token}</code>
_130 marginBottom: '16px',
_130 If you didn't try to login, you can safely ignore this email.
_130 <Text style={footer}>
_130 href="https://demo.vercel.store/"
_130 style={{ ...link, color: '#898989' }}
_130 , the famouse demo corp.
_130export default MagicLinkEmail
_130 backgroundColor: '#ffffff',
_130 paddingLeft: '12px',
_130 paddingRight: '12px',
_130 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
_130 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
_130 textDecoration: 'underline',
_130 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
_130 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
_130 marginBottom: '24px',
_130 display: 'inline-block',
_130 padding: '16px 4.5%',
_130 backgroundColor: '#f4f4f4',
_130 borderRadius: '5px',
_130 border: '1px solid #eee',
You can find a selection of React Email templates in the React Email Examples.
Deploy function to Supabase:
_10supabase functions deploy send-email --no-verify-jwt
Note down the function URL, you will need it in the next step!
- Go to the Auth Hooks section of the Supabase dashboard and create a new "Send Email hook".
- Select HTTPS as the hook type.
- Paste the function URL in the "URL" field.
- Click "Generate Secret" to generate your webhook secret and note it down.
- Click "Create" to save the hook configuration.
Store these secrets in your .env
file.
_10RESEND_API_KEY=your_resend_api_key
_10SEND_EMAIL_HOOK_SECRET=<base64_secret>
You can generate the secret in the Auth Hooks section of the Supabase dashboard. Make sure to remove the v1,whsec_
prefix!
Set the secrets from the .env
file:
_10supabase secrets set --env-file supabase/functions/.env
That's it, now your Supabase Edge Function will be triggered anytime an Auth Email needs to be send to the user!