使用 React Email 和 Resend 自定义认证邮件
使用 发送邮件钩子 在 Supabase Edge Functions 中通过 React Email 和 Resend 发送自定义认证邮件。
🌐 Use the send email hook to send custom auth emails with React Email and Resend in Supabase Edge Functions.
想直接看代码吗?看看 GitHub 上的示例。
🌐 Prefer to jump straight to the code? Check out the example on GitHub.
先决条件 #
🌐 Prerequisites
要充分利用本指南,你需要:
🌐 To get the most out of this guide, you’ll need to:
确保你已经安装了最新版本的 Supabase CLI。
🌐 Make sure you have the latest version of the Supabase CLI installed.
1. 创建 Supabase 函数 #
🌐 1. Create Supabase function
在本地创建一个新函数:
🌐 Create a new function locally:
1supabase functions new send-email2. 编辑处理函数 #
🌐 2. Edit the handler function
把以下代码粘贴到 index.ts 文件里:
🌐 Paste the following code into the index.ts file:
1import { renderAsync } from 'npm:@react-email/components@^1'2import { withSupabase } from 'npm:@supabase/server@^1'3import React from 'npm:react@^19'4import { Resend } from 'npm:resend@^6'5import { Webhook } from 'npm:standardwebhooks@^1'67import { MagicLinkEmail } from './_templates/magic-link.tsx'89const resend = new Resend(Deno.env.get('RESEND_API_KEY') as string)10const hookSecret = (Deno.env.get('SEND_EMAIL_HOOK_SECRET') as string).replace('v1,whsec_', '')1112export default {13 fetch: withSupabase({ auth: 'none' }, async (req) => {14 if (req.method !== 'POST') {15 return Response.json({ error: 'not allowed' }, { status: 400 })16 }1718 const payload = await req.text()19 const headers = Object.fromEntries(req.headers)20 const wh = new Webhook(hookSecret)21 try {22 const {23 user,24 email_data: { token, token_hash, redirect_to, email_action_type },25 } = wh.verify(payload, headers) as {26 user: {27 email: string28 }29 email_data: {30 token: string31 token_hash: string32 redirect_to: string33 email_action_type: string34 site_url: string35 token_new: string36 token_hash_new: string37 }38 }3940 const html = await renderAsync(41 React.createElement(MagicLinkEmail, {42 supabase_url: Deno.env.get('SUPABASE_URL') ?? '',43 token,44 token_hash,45 redirect_to,46 email_action_type,47 })48 )4950 const { error } = await resend.emails.send({51 from: 'welcome <onboarding@resend.dev>',52 to: [user.email],53 subject: 'Supa Custom MagicLink!',54 html,55 })56 if (error) {57 throw error58 }59 } catch (error) {60 console.log(error)61 return Response.json(62 {63 error: {64 http_code: error.code,65 message: error.message,66 },67 },68 { status: 401 }69 )70 }7172 return Response.json({})73 }),74}3. 创建 React 邮件模板 #
🌐 3. Create React Email templates
按照推荐的项目结构创建一个新的_templates文件夹,并添加一个新的magic-link.tsx文件,内容如下:
🌐 Create a new _templates folder following the recommended project structure and add a new magic-link.tsx file with the following code:
1import {2 Body,3 Container,4 Head,5 Heading,6 Html,7 Link,8 Preview,9 Text,10} from 'npm:@react-email/components@^1'11import * as React from 'npm:react@^19'1213interface MagicLinkEmailProps {14 supabase_url: string15 email_action_type: string16 redirect_to: string17 token_hash: string18 token: string19}2021export const MagicLinkEmail = ({22 token,23 supabase_url,24 email_action_type,25 redirect_to,26 token_hash,27}: MagicLinkEmailProps) => (28 <Html>29 <Head />30 <Preview>Log in with this magic link</Preview>31 <Body style={main}>32 <Container style={container}>33 <Heading style={h1}>Login</Heading>34 <Link35 href={`${supabase_url}/auth/v1/verify?token=${token_hash}&type=${email_action_type}&redirect_to=${redirect_to}`}36 target="_blank"37 style={{38 ...link,39 display: 'block',40 marginBottom: '16px',41 }}42 >43 Click here to log in with this magic link44 </Link>45 <Text style={{ ...text, marginBottom: '14px' }}>46 Or, copy and paste this temporary login code:47 </Text>48 <code style={code}>{token}</code>49 <Text50 style={{51 ...text,52 color: '#ababab',53 marginTop: '14px',54 marginBottom: '16px',55 }}56 >57 If you didn't try to login, you can safely ignore this email.58 </Text>59 <Text style={footer}>60 <Link61 href="https://demo.vercel.store/"62 target="_blank"63 style={{ ...link, color: '#898989' }}64 >65 ACME Corp66 </Link>67 , the famouse demo corp.68 </Text>69 </Container>70 </Body>71 </Html>72)7374export default MagicLinkEmail7576const main = {77 backgroundColor: '#ffffff',78}7980const container = {81 paddingLeft: '12px',82 paddingRight: '12px',83 margin: '0 auto',84}8586const h1 = {87 color: '#333',88 fontFamily:89 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",90 fontSize: '24px',91 fontWeight: 'bold',92 margin: '40px 0',93 padding: '0',94}9596const link = {97 color: '#2754C5',98 fontFamily:99 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",100 fontSize: '14px',101 textDecoration: 'underline',102}103104const text = {105 color: '#333',106 fontFamily:107 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",108 fontSize: '14px',109 margin: '24px 0',110}111112const footer = {113 color: '#898989',114 fontFamily:115 "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",116 fontSize: '12px',117 lineHeight: '22px',118 marginTop: '12px',119 marginBottom: '24px',120}121122const code = {123 display: 'inline-block',124 padding: '16px 4.5%',125 width: '90.5%',126 backgroundColor: '#f4f4f4',127 borderRadius: '5px',128 border: '1px solid #eee',129 color: '#333',130}你可以在 React Email Examples 找到一些 React 邮件模板。
🌐 You can find a selection of React Email templates in the React Email Examples.
4. 部署函数 #
🌐 4. Deploy the Function
将函数部署到 Supabase:
🌐 Deploy function to Supabase:
1supabase functions deploy send-email --no-verify-jwt记下这个函数的 URL,下一步你会用到它!
🌐 Note down the function URL, you will need it in the next step!
5. 配置发送邮件钩子 #
🌐 5. Configure the Send Email Hook
- 去 Supabase 控制面板的 Auth Hooks 部分,创建一个新的“发送邮件钩子”。
- 选择 HTTPS 作为钩子类型。
- 把函数的 URL 粘贴到“URL”字段里。
- 点击“生成密钥”来生成你的 webhook 密钥并记下来。
- 点击“创建”以保存钩子配置。
把这些秘密存到你的 .env 文件里。
🌐 Store these secrets in your .env file.
1RESEND_API_KEY=your_resend_api_key2SEND_EMAIL_HOOK_SECRET="v1,whsec_<base64_secret>"你可以在 Supabase 仪表板的 Auth Hooks 部分生成密钥。
🌐 You can generate the secret in the Auth Hooks section of the Supabase dashboard.
从 .env 文件中设置秘密:
🌐 Set the secrets from the .env file:
1supabase secrets set --env-file supabase/functions/.env现在,每当需要向用户发送认证邮件时,你的 Supabase Edge 函数都会被触发!
🌐 Now your Supabase Edge Function will be triggered anytime an Auth Email needs to be sent to the user!
更多资源 #
🌐 More resources