Documentation Index Fetch the complete documentation index at: https://docs.autosend.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This guide shows you how to integrate AutoSend with Supabase Edge Functions to send emails for authentication, notifications, and other transactional use cases. Edge Functions run at the edge, close to your users, making them perfect for handling email operations with low latency.
Prerequisites
Before you begin, make sure you have:
Quickstart
Create a Supabase Edge Function Initialize your Supabase project and create a new Edge Function: # Login to Supabase
supabase login
# Initialize your project (if not already done)
supabase init
# Create a new Edge Function
supabase functions new autosend
This creates a new function in supabase/functions/autosend/index.ts.
Install Dependencies Edge Functions support importing from standard URLs. No package installation needed!
Write the Edge Function Replace the content of supabase/functions/autosend/index.ts with: import { serve } from "https://deno.land/[email protected] /http/server.ts"
import { corsHeaders } from '../_shared/cors.ts'
serve ( async ( req ) => {
// Handle CORS preflight requests
if ( req . method === 'OPTIONS' ) {
return new Response ( 'ok' , { headers: corsHeaders })
}
try {
const { to , from , subject , html , templateId , dynamicData } = await req . json ()
// Get AutoSend API key from environment variables
const autoSendApiKey = Deno . env . get ( 'AUTOSEND_API_KEY' )
if ( ! autoSendApiKey ) {
throw new Error ( 'AUTOSEND_API_KEY not configured' )
}
// Prepare email payload
const emailPayload : any = {
to: {
email: to . email ,
name: to . name || undefined
},
from: {
email: from . email ,
name: from . name || undefined
}
}
// Add template or HTML content
if ( templateId ) {
emailPayload . templateId = templateId
if ( dynamicData ) {
emailPayload . dynamicData = dynamicData
}
} else {
emailPayload . subject = subject
emailPayload . html = html
}
// Send email via AutoSend API
const response = await fetch ( 'https://api.autosend.com/v1/mails/send' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ autoSendApiKey } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( emailPayload )
})
const data = await response . json ()
if ( ! response . ok ) {
throw new Error ( data . message || 'Failed to send email' )
}
return new Response (
JSON . stringify ({
success: true ,
emailId: data . data . emailId ,
status: data . data . status
}),
{
headers: { ... corsHeaders , 'Content-Type' : 'application/json' },
status: 200 ,
},
)
} catch ( error ) {
return new Response (
JSON . stringify ({
success: false ,
error: error . message
}),
{
headers: { ... corsHeaders , 'Content-Type' : 'application/json' },
status: 400 ,
},
)
}
})
See all 82 lines
Create Shared CORS Configuration Create a file at supabase/functions/_shared/cors.ts: export const corsHeaders = {
'Access-Control-Allow-Origin' : '*' ,
'Access-Control-Allow-Headers' : 'authorization, x-client-info, apikey, content-type' ,
}
New Step Create a .env file in your project root (for local development): AUTOSEND_API_KEY = your_autosend_api_key_here
For production, set secrets using the Supabase CLI: supabase secrets set AUTOSEND_API_KEY=your_autosend_api_key_here
Run Locally Test your function locally before deploying: supabase functions serve autosend --env-file .env --no-verify-jwt
The function will be available at: http://localhost:54321/functions/v1/autosend
Test Your Function Send a test request using cURL: curl -i --location --request POST 'http://localhost:54321/functions/v1/autosend' \
--header 'Authorization: Bearer YOUR_SUPABASE_ANON_KEY' \
--header 'Content-Type: application/json' \
--data '{
"to": {
"email": "[email protected]",
"name": "John Doe"
},
"from": {
"email": "[email protected]",
"name": "Your App"
},
"subject": "Welcome to our platform!",
"html": "<h1>Hello John!</h1><p>Welcome aboard!</p>"
}'
Deploy to Production Once tested, deploy your function: supabase functions deploy autosend
Your function will be available at: https://YOUR_PROJECT_REF.supabase.co/functions/v1/autosend
Usage Examples
const { data , error } = await supabase . functions . invoke ( 'autosend' , {
body: {
to: {
email: '[email protected]' ,
name: 'Jane Smith'
},
from: {
email: '[email protected]' ,
name: 'MyApp'
},
subject: 'Welcome!' ,
html: '<h1>Welcome to MyApp!</h1><p>We are excited to have you.</p>'
}
})
if ( error ) {
console . error ( 'Error sending email:' , error )
} else {
console . log ( 'Email sent:' , data )
}
Send Using AutoSend Template
const { data , error } = await supabase . functions . invoke ( 'autosend' , {
body: {
to: {
email: '[email protected]' ,
name: 'Jane Smith'
},
from: {
email: '[email protected]' ,
name: 'MyApp'
},
templateId: 'tmpl_welcome_email' ,
dynamicData: {
firstName: 'Jane' ,
loginUrl: 'https://app.example.com/login'
}
}
})
const sendEmail = async () => {
const response = await fetch (
'https://YOUR_PROJECT_REF.supabase.co/functions/v1/autosend' ,
{
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ supabaseAnonKey } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
to: {
email: '[email protected]' ,
name: 'John Doe'
},
from: {
email: '[email protected]' ,
name: 'MyApp'
},
subject: 'Order Confirmation' ,
html: '<p>Your order has been confirmed!</p>'
})
}
)
const data = await response . json ()
return data
}
Integration with Supabase Auth
You can use AutoSend to send custom authentication emails by integrating with Supabase Auth Hooks.
Create Auth Hook Function supabase functions new send-auth-email
Implement Auth Hook Handler import { serve } from "https://deno.land/[email protected] /http/server.ts"
serve ( async ( req ) => {
try {
const payload = await req . json ()
const { event_type , user , token_hash , redirect_to } = payload
const autoSendApiKey = Deno . env . get ( 'AUTOSEND_API_KEY' )
let templateId : string
let dynamicData : any = {}
// Map event types to templates
switch ( event_type ) {
case 'user.signup' :
templateId = 'tmpl_signup_confirmation'
dynamicData = {
confirmationUrl: ` ${ redirect_to } ?token_hash= ${ token_hash } &type=signup` ,
email: user . email
}
break
case 'user.password_recovery' :
templateId = 'tmpl_password_reset'
dynamicData = {
resetUrl: ` ${ redirect_to } ?token_hash= ${ token_hash } &type=recovery` ,
email: user . email
}
break
case 'user.email_change' :
templateId = 'tmpl_email_change'
dynamicData = {
confirmationUrl: ` ${ redirect_to } ?token_hash= ${ token_hash } &type=email_change` ,
newEmail: user . new_email
}
break
default :
throw new Error ( `Unsupported event type: ${ event_type } ` )
}
// Send email via AutoSend
const response = await fetch ( 'https://api.autosend.com/v1/mails/send' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ autoSendApiKey } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
to: {
email: user . email
},
from: {
email: '[email protected]' ,
name: 'Your App'
},
templateId ,
dynamicData
})
})
const data = await response . json ()
if ( ! response . ok ) {
throw new Error ( data . message || 'Failed to send auth email' )
}
return new Response (
JSON . stringify ({ success: true }),
{
headers: { 'Content-Type' : 'application/json' },
status: 200 ,
},
)
} catch ( error ) {
return new Response (
JSON . stringify ({ error: error . message }),
{
headers: { 'Content-Type' : 'application/json' },
status: 400 ,
},
)
}
})
See all 85 lines
Error Handling
Implement robust error handling for production:
import { serve } from 'https://deno.land/[email protected] /http/server.ts' ;
serve ( async ( req ) => {
try {
const payload = await req . json ();
// Validate required fields
if ( ! payload . to ?. email ) {
throw new Error ( 'Recipient email is required' );
}
if ( ! payload . from ?. email ) {
throw new Error ( 'Sender email is required' );
}
const autoSendApiKey = Deno . env . get ( 'AUTOSEND_API_KEY' );
if ( ! autoSendApiKey ) {
throw new Error ( 'AutoSend API key not configured' );
}
const response = await fetch ( 'https://api.autosend.com/v1/mails/send' , {
method: 'POST' ,
headers: {
Authorization: `Bearer ${ autoSendApiKey } ` ,
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ( payload ),
});
const data = await response . json ();
// Handle AutoSend API errors
if ( ! response . ok ) {
console . error ( 'AutoSend API Error:' , data );
switch ( response . status ) {
case 400 :
throw new Error ( `Validation error: ${ data . message } ` );
case 401 :
throw new Error ( 'Invalid API key' );
case 403 :
throw new Error ( 'Domain not verified or insufficient permissions' );
case 429 :
throw new Error ( 'Rate limit exceeded. Please try again later.' );
default :
throw new Error ( data . message || 'Failed to send email' );
}
}
return new Response (
JSON . stringify ({
success: true ,
emailId: data . data . emailId ,
status: data . data . status ,
}),
{
headers: { 'Content-Type' : 'application/json' },
status: 200 ,
},
);
} catch ( error ) {
console . error ( 'Function Error:' , error );
return new Response (
JSON . stringify ({
success: false ,
error: error . message ,
}),
{
headers: { 'Content-Type' : 'application/json' },
status: 400 ,
},
);
}
});
See all 76 lines
Best Practices
Always use environment variables for sensitive data: // ✅ Good
const apiKey = Deno . env . get ( 'AUTOSEND_API_KEY' )
// ❌ Bad - Never hardcode
const apiKey = 'as_123456789'
Validate email formats before sending: function isValidEmail ( email : string ) : boolean {
const emailRegex = / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ /
return emailRegex . test ( email )
}
if ( ! isValidEmail ( payload . to . email )) {
throw new Error ( 'Invalid email address' )
}
Protect your function from abuse: // Use Supabase Rate Limiting or implement custom logic
const userRateLimit = await checkUserRateLimit ( userId )
if ( ! userRateLimit . allowed ) {
throw new Error ( 'Rate limit exceeded' )
}
Always send from verified domains in AutoSend to ensure deliverability.
Learn how to verify domains →
Testing
Test Function Locally
# Start local development server
supabase functions serve send-email --env-file .env
# Test with curl
curl -i --location --request POST 'http://localhost:54321/functions/v1/send-email' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
--header 'Content-Type: application/json' \
--data '{
"to": { "email": "[email protected]" },
"from": { "email": "[email protected]" },
"subject": "Test Email",
"html": "<p>This is a test</p>"
}'