认证

发送邮件钩子

使用自定义邮件提供商发送认证消息


发送邮件钩子在邮件发送前运行,为邮件发送提供了灵活性。您可以使用此钩子配置备用邮件提供商或为邮件添加国际化支持。

邮件发送行为

邮件发送取决于两个设置:邮件提供商和认证钩子状态。

邮件提供商认证钩子结果
已启用已启用认证钩子处理邮件发送(不使用SMTP)
已启用已禁用SMTP处理邮件发送(如果配置了自定义SMTP则使用自定义,否则使用默认)
已禁用已启用邮件注册功能禁用
已禁用已禁用邮件注册功能禁用

输入参数

字段类型描述
userUser尝试登录的用户对象。
emailobject邮件发送流程的元数据。包含一次性密码(OTP)和token_hash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{ "user": { "id": "8484b834-f29e-4af2-bf42-80644d154f76", "aud": "authenticated", "role": "authenticated", "email": "valid.email@supabase.io", "phone": "", "app_metadata": { "provider": "email", "providers": ["email"] }, "user_metadata": { "email": "valid.email@supabase.io", "email_verified": false, "phone_verified": false, "sub": "8484b834-f29e-4af2-bf42-80644d154f76" }, "identities": [ { "identity_id": "bc26d70b-517d-4826-bce4-413a5ff257e7", "id": "8484b834-f29e-4af2-bf42-80644d154f76", "user_id": "8484b834-f29e-4af2-bf42-80644d154f76", "identity_data": { "email": "valid.email@supabase.io", "email_verified": false, "phone_verified": false, "sub": "8484b834-f29e-4af2-bf42-80644d154f76" }, "provider": "email", "last_sign_in_at": "2024-05-14T12:56:33.824231484Z", "created_at": "2024-05-14T12:56:33.824261Z", "updated_at": "2024-05-14T12:56:33.824261Z", "email": "valid.email@supabase.io" } ], "created_at": "2024-05-14T12:56:33.821567Z", "updated_at": "2024-05-14T12:56:33.825595Z", "is_anonymous": false }, "email_data": { "token": "305805", "token_hash": "7d5b7b1964cf5d388340a7f04f1dbb5eeb6c7b52ef8270e1737a58d0", "redirect_to": "http://localhost:3000/", "email_action_type": "signup", "site_url": "http://localhost:9999", "token_new": "", "token_hash_new": "" }}

输出

  • 不需要任何输出。返回状态码200的空响应即表示成功响应。

您可以通过"发送邮件"钩子配置Resend作为自定义邮件提供商。这使您能够利用Resend开发者友好的API发送邮件,并使用React Email管理邮件模板。如需更高级的React Email教程,请参考本指南

如果想通过Supabase Resend集成(使用Resend的SMTP服务器)发送邮件,请查看此集成

创建包含以下环境变量的.env文件:

1
2
RESEND_API_KEY="your_resend_api_key"SEND_EMAIL_HOOK_SECRET="v1,whsec_<base64_secret>"

在Supabase项目中设置密钥:

1
supabase secrets set --env-file .env

创建新的边缘函数:

1
supabase functions new send-email

将以下代码添加到边缘函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { Webhook } from "https://esm.sh/standardwebhooks@1.0.0";import { Resend } from "npm:resend";const resend = new Resend(Deno.env.get("RESEND_API_KEY") as string);const hookSecret = (Deno.env.get("SEND_EMAIL_HOOK_SECRET") as string).replace("v1,whsec_", "");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); const wh = new Webhook(hookSecret); try { const { user, email_data } = wh.verify(payload, headers) as { user: { email: string; }; email_data: { token: string; token_hash: string; redirect_to: string; email_action_type: string; site_url: string; token_new: string; token_hash_new: string; }; }; const { error } = await resend.emails.send({ from: "welcome <onboarding@example.com>", to: [user.email], subject: "Welcome to my site!", text: `Confirm you signup with this code: ${email_data.token}`, }); if (error) { throw error; } } catch (error) { return new Response( JSON.stringify({ error: { http_code: error.code, message: error.message, }, }), { status: 401, headers: { "Content-Type": "application/json" }, }, ); } const responseHeaders = new Headers(); responseHeaders.set("Content-Type", "application/json"); return new Response(JSON.stringify({}), { status: 200, headers: responseHeaders, });});

部署边缘函数并配置为钩子

1
supabase functions deploy send-email --no-verify-jwt