Prerequisites
To get the most out of this guide, you’ll need to:- Create a SendPost Account
- Supabase Account (free tier works)
- Supabase CLI installed
- A Sub-Account API Key from your SendPost dashboard
You can find your API keys in your SendPost Dashboard. Make sure to use your Sub-Account API Key for sending emails.
1. Install Supabase CLI
npm install -g supabase
2. Initialize Supabase Project
supabase init
supabase login
supabase link --project-ref your-project-ref
3. Create Edge Function
Create a new edge function:supabase functions new send-email
supabase/
functions/
send-email/
index.ts
4. Basic Email Function
Updatesupabase/functions/send-email/index.ts:
TypeScript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';
interface EmailRequest {
to: string;
subject: string;
htmlBody: string;
textBody?: string;
}
serve(async (req) => {
// Handle CORS
if (req.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
try {
const { to, subject, htmlBody, textBody }: EmailRequest = await req.json();
if (!to || !subject || !htmlBody) {
return new Response(
JSON.stringify({
success: false,
error: 'Missing required fields: to, subject, htmlBody',
}),
{
status: 400,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
// Prepare email message
const emailMessage = {
from: {
email: 'hello@playwithsendpost.io',
name: 'SendPost',
},
to: [{ email: to }],
subject,
htmlBody,
textBody: textBody || htmlBody.replace(/<[^>]*>/g, ''),
trackOpens: true,
trackClicks: true,
};
// Send email via SendPost API
const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-SubAccount-ApiKey': SENDPOST_API_KEY,
},
body: JSON.stringify(emailMessage),
});
if (!response.ok) {
const error = await response.text();
throw new Error(`SendPost API error: ${error}`);
}
const result = await response.json();
return new Response(
JSON.stringify({
success: true,
messageId: result.messageId,
}),
{
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
} catch (error) {
console.error('SendPost error:', error);
return new Response(
JSON.stringify({
success: false,
error: error.message,
}),
{
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
});
5. Set Environment Variables
Set the secret in Supabase:supabase secrets set SENDPOST_API_KEY=your_sub_account_api_key
- Go to Project Settings → Edge Functions
- Add secret:
SENDPOST_API_KEY
6. Deploy Function
Deploy the function:supabase functions deploy send-email
7. Common Use Cases
Welcome Email Function
Createsupabase/functions/welcome-email/index.ts:
TypeScript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
try {
const { email, firstName } = await req.json();
if (!email || !firstName) {
return new Response(
JSON.stringify({
success: false,
error: 'Missing required fields: email, firstName',
}),
{ status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
);
}
const emailMessage = {
from: {
email: 'hello@playwithsendpost.io',
name: 'SendPost',
},
to: [
{
email,
name: firstName,
customFields: { firstName },
},
],
subject: 'Welcome {{firstName}}!',
htmlBody: `
<h1>Welcome, {{firstName}}!</h1>
<p>Thank you for joining us. We're excited to have you on board.</p>
<p>Get started by exploring our features:</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
<p>If you have any questions, just reply to this email.</p>
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
`,
textBody: `
Welcome, {{firstName}}!
Thank you for joining us. We're excited to have you on board.
Get started by exploring our features:
- Feature 1
- Feature 2
- Feature 3
If you have any questions, just reply to this email.
Unsubscribe: {{unsubscribe}}
`,
groups: ['welcome'],
trackOpens: true,
trackClicks: true,
};
const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-SubAccount-ApiKey': SENDPOST_API_KEY,
},
body: JSON.stringify(emailMessage),
});
const result = await response.json();
return new Response(
JSON.stringify({
success: true,
messageId: result.messageId,
}),
{
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
} catch (error) {
return new Response(
JSON.stringify({
success: false,
error: error.message,
}),
{
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
});
Password Reset Email
Createsupabase/functions/password-reset/index.ts:
TypeScript
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';
serve(async (req) => {
if (req.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
},
});
}
try {
const { email, resetToken, firstName } = await req.json();
const appUrl = Deno.env.get('APP_URL') || 'https://yourapp.com';
const resetUrl = `${appUrl}/reset-password?token=${resetToken}`;
const emailMessage = {
from: {
email: 'hello@playwithsendpost.io',
name: 'SendPost',
},
to: [
{
email,
name: firstName || 'User',
customFields: {
firstName: firstName || 'User',
resetUrl,
},
},
],
subject: 'Reset Your Password',
htmlBody: `
<h2>Hello {{firstName}},</h2>
<p>We received a request to reset your password. Click the button below:</p>
<p>
<a href="{{resetUrl}}" style="background-color: #5750EC; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
Reset Password
</a>
</p>
<p>Or copy and paste this link: {{resetUrl}}</p>
<p>This link will expire in 1 hour.</p>
<p>If you didn't request this, please ignore this email.</p>
`,
groups: ['password-reset'],
trackClicks: true,
};
const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-SubAccount-ApiKey': SENDPOST_API_KEY,
},
body: JSON.stringify(emailMessage),
});
const result = await response.json();
return new Response(
JSON.stringify({
success: true,
messageId: result.messageId,
}),
{
status: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
} catch (error) {
return new Response(
JSON.stringify({
success: false,
error: error.message,
}),
{
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
);
}
});
8. Invoke Function
From Client
TypeScript
const { data, error } = await supabase.functions.invoke('send-email', {
body: {
to: 'user@example.com',
subject: 'Hello from Supabase!',
htmlBody: '<h1>Hello!</h1><p>This email was sent from Supabase Edge Functions.</p>',
},
});
Via HTTP
curl -X POST \
'https://your-project-ref.supabase.co/functions/v1/send-email' \
-H 'Authorization: Bearer YOUR_ANON_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "user@example.com",
"subject": "Test Email",
"htmlBody": "<h1>Hello!</h1>"
}'
9. Testing Locally
Run locally:supabase functions serve send-email
curl -X POST http://localhost:54321/functions/v1/send-email \
-H 'Authorization: Bearer YOUR_ANON_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "user@example.com",
"subject": "Test",
"htmlBody": "<h1>Test</h1>"
}'
Make sure your sender email domain is verified in your SendPost account before sending emails.
10. Next Steps
Explore more examples and use cases:Supabase Edge Functions
Learn more about Supabase Edge Functions
Deno Documentation
Learn more about Deno runtime
Quickstart Example
View a complete working example on GitHub