如何在Supabase谷歌登录场景下给首次登录用户发送邮件?
Supabase谷歌登录首次用户提示邮件实现方案
方案一:数据库触发器 + Supabase Edge Functions(推荐,后端自动处理)
这种方案无需客户端介入,完全在Supabase生态内完成,可靠性更高,避免客户端逻辑遗漏。
创建用户扩展表(可选但推荐)
为了跟踪邮件发送状态,建议创建一个profiles表关联auth.users:CREATE TABLE profiles ( user_id UUID REFERENCES auth.users(id) PRIMARY KEY, email TEXT UNIQUE NOT NULL, welcome_email_sent BOOLEAN DEFAULT false, created_at TIMESTAMP WITH TIME ZONE DEFAULT TIME ZONE 'utc'::text NOT NULL );编写发送邮件的Edge Function
创建一个Edge Function来处理邮件发送逻辑,支持幂等性(避免重复发送):import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' import { sendMail } from 'https://esm.sh/deno-mailer' Deno.serve(async (req) => { const supabaseAdmin = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! ) const { record } = await req.json() const userId = record.id const userEmail = record.email // 检查是否已发送过欢迎邮件 const { data: profile } = await supabaseAdmin .from('profiles') .select('welcome_email_sent') .eq('user_id', userId) .single() if (profile?.welcome_email_sent) { return new Response(JSON.stringify({ status: 'already sent' }), { status: 200 }) } // 发送欢迎邮件 try { await sendMail({ from: '你的应用 <support@yourapp.com>', to: userEmail, subject: '欢迎加入我们的应用!', html: '<p>感谢您首次登录,这是为您准备的提示内容...</p>' }) // 更新状态标记邮件已发送 await supabaseAdmin .from('profiles') .update({ welcome_email_sent: true }) .eq('user_id', userId) return new Response(JSON.stringify({ status: 'success' }), { status: 200 }) } catch (err) { return new Response(JSON.stringify({ error: err.message }), { status: 500 }) } })创建数据库触发器
监听auth.users表的INSERT事件,触发Edge Function:CREATE OR REPLACE FUNCTION trigger_welcome_email() RETURNS TRIGGER AS $$ BEGIN -- 先初始化profiles记录(避免冲突) INSERT INTO profiles (user_id, email) VALUES (NEW.id, NEW.email) ON CONFLICT (user_id) DO NOTHING; -- 调用Edge Function PERFORM http_post( 'https://<你的项目ID>.supabase.co/functions/v1/send-welcome-email', json_build_object('record', NEW)::text, 'application/json', ARRAY[('Authorization', 'Bearer ' || current_setting('supabase.service_role_key'))] ); RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE TRIGGER on_new_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION trigger_welcome_email();
方案二:客户端判断 + 后端邮件接口
如果需要在客户端做额外逻辑(比如引导用户完成资料填写后再发邮件),可以用这种方案:
登录后判断是否为首次用户
用户完成谷歌登录后,查询自定义的profiles表,若不存在记录则判定为首次登录:async function handleGoogleLogin() { const { error } = await supabase.auth.signInWithOAuth({ provider: 'google' }); if (error) return; const { data: { user } } = await supabase.auth.getUser(); if (!user) return; // 查询用户是否存在于profiles表 const { data: profile, error: profileErr } = await supabase .from('profiles') .select('id') .eq('user_id', user.id) .single(); // 若不存在则是首次登录 if (profileErr && profileErr.code === 'PGRST116') { // 调用邮件接口发送提示 await fetch('/api/send-welcome-email', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: user.email, userId: user.id }) }); // 创建profiles记录 await supabase.from('profiles').insert({ user_id: user.id, email: user.email }); } }后端邮件接口实现
用你熟悉的后端框架(比如Node.js/Express)实现邮件发送接口,同样要处理幂等性:// Express示例 app.post('/api/send-welcome-email', async (req, res) => { const { email, userId } = req.body; const supabaseAdmin = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY); // 检查邮件是否已发送 const { data: profile } = await supabaseAdmin .from('profiles') .select('welcome_email_sent') .eq('user_id', userId) .single(); if (profile?.welcome_email_sent) { return res.status(200).json({ status: 'already sent' }); } // 发送邮件(用你选择的邮件服务,比如Nodemailer) await transporter.sendMail({ from: '你的应用 <support@yourapp.com>', to: email, subject: '欢迎首次登录!', text: '这是给您的提示邮件内容...' }); // 更新状态 await supabaseAdmin .from('profiles') .update({ welcome_email_sent: true }) .eq('user_id', userId); res.status(200).json({ status: 'success' }); });
注意事项
- 幂等性:必须添加邮件发送状态标记,避免因触发器重复触发或客户端重复请求导致多次发送邮件。
- 环境变量:邮件服务密钥、Supabase的服务角色密钥等敏感信息要存在环境变量中,禁止硬编码。
- 测试:先用Supabase本地开发环境测试触发器和Edge Function,确保逻辑正常后再部署到生产环境。
内容的提问来源于stack exchange,提问作者Eran
相关产品推荐
相关产品推荐

