Nodemailer适配Firebase云函数异常:无报错但无法发送邮件
问题排查与修复方案
1. 云函数核心问题:未正确处理异步操作与返回值
你的sendVerificationCode是HTTPS Callable类型函数,这类函数要求返回Promise来确保Firebase等待异步操作完成。原代码使用回调式的transporter.sendMail,函数会直接返回undefined,导致云函数提前终止,邮件发送流程被中断。同时,你错误使用了res.send——Callable函数没有res对象,需通过返回值或抛出错误来传递结果。
修复后的云函数代码:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); const nodemailer = require("nodemailer"); admin.initializeApp(); // 使用Firebase环境变量存储敏感信息(推荐) const SENDER_EMAIL = functions.config().gmail.email; const SENDER_PASSWORD = functions.config().gmail.password; // 简化Gmail配置:指定service后无需手动设置host等参数 const transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: SENDER_EMAIL, pass: SENDER_PASSWORD } }); exports.sendVerificationCode = functions.https.onCall(async (data, context) => { // 从前端接收目标邮箱(原代码硬编码to地址,需改成动态接收) const targetEmail = data.email; if (!targetEmail) { throw new functions.https.HttpsError('invalid-argument', '目标邮箱不能为空'); } const mailOptions = { from: SENDER_EMAIL, // 必须与auth中的user一致 to: targetEmail, subject: 'Email from Firebase', text: 'TEST TEST' }; try { const info = await transporter.sendMail(mailOptions); console.log('Email sent:', info.response); return { message: '邮件发送成功' }; } catch (error) { console.error('发送失败:', error); throw new functions.https.HttpsError('internal', '邮件发送失败', error.message); } });
2. Gmail SMTP权限配置
Gmail默认禁止普通密码通过第三方应用登录,你需要:
- 开启两步验证(2FA),然后生成应用专用密码(App Password),用这个密码代替原密码。
- 如果未开启2FA,需在Google账号设置中开启“不太安全的应用访问”(但此方式已逐步被Google禁用,优先推荐App Password)。
3. Swift调用代码修复
原Swift代码未传递目标邮箱参数,需修改为传递email参数:
func sendVerificationCode(to email: String, uid: String) { let functions = Functions.functions() functions.httpsCallable("sendVerificationCode").call(["email": email]) { result, error in if let error = error as NSError? { if error.domain == FunctionsErrorDomain { let code = FunctionsErrorCode(rawValue: error.code) let message = error.localizedDescription let details = error.userInfo[FunctionsErrorDetailsKey] print("邮件发送失败: \(code ?? .unknown) - \(message), 详情: \(details ?? "")") } else { print("未知错误: \(error.localizedDescription)") } } else { print("验证码发送成功") } } }
4. 部署与测试注意事项
- 设置Firebase环境变量:
firebase functions:config:set gmail.email="你的邮箱地址" gmail.password="应用专用密码" - 重新部署云函数:
firebase deploy --only functions - 查看云函数日志:通过Firebase控制台的“函数”→“日志”查看详细错误信息,这是排查发送失败的关键。
内容的提问来源于stack exchange,提问作者Nexteon
相关产品推荐
相关产品推荐

