How to Use Notify with Supabase Edge Functions
Send email from a Supabase Edge Function with Deno fetch and x-api-key.
Call Notify from a Supabase Edge Function when auth hooks, database webhooks, or your app need to send transactional email. Keep the API key in Edge Function secrets.
Prerequisites
- API key — generated when you sign up
- Verified domain (optional) — required for production sends from a custom
fromaddress - Supabase CLI and a project with Edge Functions enabled
Set the secret
supabase secrets set NOTIFY_API_KEY=your_api_key_here
Edge Function
Create supabase/functions/send-email/index.ts:
import { serve } from 'https://deno.land/std@0.224.0/http/server.ts';
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers':
'authorization, x-client-info, apikey, content-type'
};
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders });
}
try {
const { to, subject, message, from } = await req.json();
if (!to || !subject || !message) {
return new Response(
JSON.stringify({ error: 'to, subject, and message are required' }),
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
);
}
const apiKey = Deno.env.get('NOTIFY_API_KEY');
if (!apiKey) {
return new Response(JSON.stringify({ error: 'NOTIFY_API_KEY not set' }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
const response = await fetch('https://notify.cx/api/email/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
to,
subject,
message,
...(from ? { from } : {})
})
});
const data = await response.json();
return new Response(JSON.stringify(data), {
status: response.status,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({ error: String(error) }), {
status: 500,
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
});
}
});
Deploy:
supabase functions deploy send-email
Invoke from your app (or another Edge Function) with the project’s anon/service role headers as usual for Supabase Functions.
Auth hook example (password reset)
When you own the reset flow yourself, generate a token in your backend, then call the Edge Function (or Notify directly) with HTML that includes the reset link. For a full Next.js App Router walkthrough, see Send password reset emails.
await fetch(`${Deno.env.get('SUPABASE_URL')}/functions/v1/send-email`, {
method: 'POST',
headers: {
Authorization: `Bearer ${Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: user.email,
subject: 'Reset your password',
message: `<p>Reset link: <a href="${resetUrl}">${resetUrl}</a></p>`
})
});