supabase/functions/send-auth-email/index.ts
import { Webhook } from "https://esm.sh/standardwebhooks@1.0.0";
const hookSecret = (Deno.env.get("SEND_EMAIL_HOOK_SECRET") as string)
.replace("v1,whsec_", "");
const notixKey = Deno.env.get("NOTIX_API_KEY") as string;
const SUBJECTS: Record<string, string> = {
signup: "Confirm your Acme account",
magiclink: "Your Acme sign-in link",
recovery: "Reset your Acme password",
invite: "You have been invited to Acme",
email_change: "Confirm your new email address",
};
Deno.serve(async (req) => {
if (req.method !== "POST") return new Response("not allowed", { status: 400 });
const payload = await req.text();
const headers = Object.fromEntries(req.headers);
try {
const { user, email_data } = new Webhook(hookSecret).verify(payload, headers) as {
user: { email: string };
email_data: {
token: string;
token_hash: string;
redirect_to: string;
email_action_type: string;
site_url: string;
};
};
const type = email_data.email_action_type;
const link =
`${email_data.site_url}/auth/confirm?token_hash=${email_data.token_hash}` +
`&type=${type}&next=${encodeURIComponent(email_data.redirect_to)}`;
const res = await fetch("https://app.usenotix.dev/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${notixKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "Acme <no-reply@acme.com>",
to: user.email,
subject: SUBJECTS[type] ?? "Your Acme account",
html: `<p><a href="${link}">Continue to Acme</a></p>
<p>Or enter this code: <strong>${email_data.token}</strong></p>`,
}),
});
if (!res.ok) {
const body = await res.text();
throw new Error(`notix ${res.status}: ${body}`);
}
} catch (error) {
return Response.json(
{ error: { http_code: 500, message: (error as Error).message } },
{ status: 500 },
);
}
return Response.json({});
});