如何在Firebase Cloud Functions中以谷歌认证用户身份发送Gmail邮件?
解决方案
方案一:通过Gmail API + OAuth2授权实现以用户邮箱发件
由于你的用户均通过谷歌账户登录,可借助Gmail API的OAuth2授权机制,让用户授予应用发送邮件的权限,从而以用户自身邮箱作为发件人发送邀请:
申请额外OAuth2权限
在你的谷歌云项目中,为OAuth2客户端ID添加https://www.googleapis.com/auth/gmail.send权限(仅发送权限,无需读取用户邮箱)。用户登录时,引导其授权该权限。存储刷新令牌
用户授权成功后,会返回refresh_token(仅首次授权或用户重新授权时会返回),将此令牌加密后存储在Firebase Auth的用户自定义属性或Firestore中(务必加密,避免泄露)。云函数中调用Gmail API发送邮件
在Firebase Cloud Functions中,通过刷新令牌获取临时访问令牌,再调用Gmail API发送邮件。示例代码:
const { google } = require('googleapis'); const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(); exports.sendInviteEmail = functions.https.onCall(async (data, context) => { if (!context.auth) { throw new functions.https.HttpsError('unauthenticated', '用户未登录'); } // 从Firestore获取加密的refresh_token并解密 const userDoc = await admin.firestore().collection('users').doc(context.auth.uid).get(); const refreshToken = decrypt(userDoc.data().refreshToken); // 自行实现解密逻辑 // 配置OAuth2客户端 const oauth2Client = new google.auth.OAuth2( functions.config().google.client_id, functions.config().google.client_secret, '你的回调URL' ); oauth2Client.setCredentials({ refresh_token: refreshToken }); // 调用Gmail API发送邮件 const gmail = google.gmail({ version: 'v1', auth: oauth2Client }); const emailContent = [ `From: ${data.userName} <${data.userEmail}>`, `To: ${data.recipientEmail}`, 'Subject: 邀请你加入XX应用', '', `你好,${data.recipientName},${data.userName}邀请你加入XX应用,点击链接:${data.inviteLink}` ].join('\n'); const encodedEmail = Buffer.from(emailContent).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); try { await gmail.users.messages.send({ userId: 'me', requestBody: { raw: encodedEmail } }); return { success: true }; } catch (error) { throw new functions.https.HttpsError('internal', '发送邮件失败', error); } });
- 注意事项
- 刷新令牌需妥善加密存储,避免泄露导致用户邮箱被滥用;
- Gmail API有发送配额,普通账户每天限制约100封,你的场景(每人每年<5封)完全满足;
- 授权流程需在前端完成,确保用户明确知晓授权内容。
方案二:代理发件+配置SPF/DKIM(无需用户授权)
若不想让用户额外授权,可采用代理发件模式,让收件人看到的发件人是用户邮箱,实际由应用账户发送:
- 设置邮件头
发送邮件时,设置From为"用户姓名 <user@example.com>",同时设置Reply-To为用户邮箱,让收件人回复时直接发给用户。示例:
const nodemailer = require('nodemailer'); const transporter = nodemailer.createTransport({ service: 'Gmail', auth: { user: '你的应用邮箱', pass: '应用专用密码' } }); const mailOptions = { from: `${userName} <${userEmail}>`, // 显示的发件人 replyTo: userEmail, // 回复地址 to: recipientEmail, subject: '邀请你加入XX应用', text: `你好,${recipientName},${userName}邀请你加入XX应用,点击链接:${inviteLink}` };
- 配置SPF和DKIM
- 在你的域名DNS中添加SPF记录,允许应用邮箱的服务器发送邮件;
- 若使用Gmail作为发件服务器,需确保应用邮箱已配置DKIM,避免邮件被标记为垃圾邮件。
- 注意事项
- 部分邮件服务商可能会在发件人旁标注"via 应用域名",但不影响收件人识别;
- 此方案无需用户额外操作,体验更流畅,适合你的事务性邀请场景。
内容的提问来源于stack exchange,提问作者Peter Varga Developer
相关产品推荐
相关产品推荐

