When one of your customers buys a product or a subscription ends, you will probably want to send an email. But the workflow for doing so is not always obvious.
In this article, I will show you how to set up transactional emails for your product using Lemon Squeezy and the Edge Functions from Supabase (which can now be self-hosted since their 7th launch week π₯).
If you already have Supabase initialized inside your project (i.e., you have a supabase
folder and the CLI installed), skip this section.
Otherwise, log in to your Supabase account using the following command:
supabase login
Supabase CLI reference for this command
Youβll need an access token, which you can generate through your Supabase Dashboard by going to the βAccess Tokensβ page.
Once youβve logged in, initialize Supabase inside your project with the following command:
supabase init
Supabase Documentation for this command
Bravo, now you should have a supabase
folder inside your project π₯³
The last step is very straightforward. Simply enter this command to create your first Edge Function:
supabase functions new purchase-emails
You should have something similar to this in your project folder:
π‘ Supabase Edge Functions use Deno. If you want to integrate the Deno language server with your editor, follow these steps.
Next, letβs write a simple function, deploy it, and check that it works.
import { serve } from "https://deno.land/[email protected]/http/server.ts"
console.log('hello toto')
serve(async (req: any) => {
return new Response(
JSON.stringify({
message: 'Success!'
}),
{ headers: { "Content-Type": "application/json" } }
)
})
Deploy the function by running this command:
supabase functions deploy purchase-emails
π€©Β And the magic happened! Go to your Supabase dashboard, in the "Edge Functions" part of your project. You should see your function:
Click on it to access a VERY useful page: you have access to a lot of details about your function, live logs, metrics an invocations. Incredibly helpful when you need to debug!
If you're using Lemon Squeezy, go to your dashboard and then navigate to Settings > Webhooks. Click on the β+β button to create your first webhook.
In the βCallback URLβ field, enter your Supabase Edge Function URL, which you can find on its details page. It will look something like this: https://xxxxxxxxxxxxxxx.functions.supabase.co/purchase-emails
Enter a random value in the βSigning secretβ field, and check the updates you want to send a webhook for. In this tutorial, weβll use the order_created
update.
Save your webhook.
There are two more things you need to know:
Lemon Squeezy webhooks section with the latest webhooks deliveries
Finally, we will write the code that will allow us to retrieve the information sent by our webhook and send a purchase confirmation email to the user.
To retrieve the webhook data, simply add this line at the beginning of our serve
function:
const event = await req.json()
The event
constant will contain all the information sent by Lemon Squeezy. Refer to their documentation to see what this data looks like.
In this tutorial, weβll need the customer email, which is located in data.attributes.user_email
. We just have to make our API call to our email sending provider with the user's email.
Here's an example using MailerSend and a template:
import { serve } from "https://deno.land/[email protected]/http/server.ts"
serve(async (req: any) => {
const event = await req.json()
try {
await fetch(`https://api.mailersend.com/v1/email`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${Deno.env.get("MAILERSEND_TOKEN")}`
},
body: JSON.stringify({
"from": {
"email": "[email protected]",
"name": "Uneed"
},
"to": [
{
"email": event.data.attributes.user_email,
"name": event.data.attributes.user_email
},
],
"subject": "Uneed - Your Skip the waiting line purchase",
"template_id": "xxxxxxxxx",
})
})
return new Response(
JSON.stringify({
message: 'Success!'
}),
{ headers: { "Content-Type": "application/json" } }
)
} catch (e) {
throw new Error('Error :/')
}
})
If you want to verify the Lemon Squeezy signature, itβs getting a bit more complicated:
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import * as crypto from "https://deno.land/[email protected]/node/crypto.ts"
serve(async (req: any) => {
const rawBody = await req.text()
const event = JSON.parse(rawBody)
const signature = req.headers.get('X-Signature') || ''
const hmac = crypto.createHmac('sha256', Deno.env.get("LS_SIGNATURE_KEY"))
hmac.update(rawBody)
const digest = hmac.digest('hex')
if (signature !== digest) {
throw new Error('Invalid signature.')
} else {
await fetch(`https://api.mailersend.com/v1/email`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${Deno.env.get("MAILERSEND_TOKEN")}`
},
body: JSON.stringify({
"from": {
"email": "[email protected]",
"name": "Uneed"
},
"to": [
{
"email": event.data.attributes.user_email,
"name": event.data.attributes.user_email
},
],
"subject": "Uneed - Your Skip the waiting line purchase",
"template_id": "xxxxxxxx",
})
})
return new Response(
JSON.stringify({
message: 'Success!'
}),
{ headers: { "Content-Type": "application/json" } }
)
}
})
And that's it! π With this function, you can handle all of your product purchases. Supabase recommends "developing fat functions" in their documentation, which means that you should develop a few large functions instead of many small functions.
Be sure to add your product to Uneed and skip the waiting line to receive an email from a Supabase Edge Function π
Automatic Open Graph Image Generator
Our new Automatic OG Image Generator is the perfect tool for creating OG images quickly and easily
The best alternatives to Typeform in 2024
Typeform is a popular online form and survey tool used by many businesses and individuals. However, there are other options out there that offer similar or even better features.