Firebase Cloud Function发送会议请求邮件遇权限拒绝问题求助
问题:Cloud Functions触发邮件发送时出现PERMISSION_DENIED错误
我正在开发一款Flutter应用,支持用户发起会议请求。当A用户向B用户发起请求时,B用户应收到提醒邮件。每次创建新请求时,meeting_requests集合会新增一则文档。我使用Google Cloud Functions结合nodemailer编写了以下代码,用于在请求创建时发送邮件:
const transporter = nodemailer.createTransport({ service: "gmail", auth: { user: <MY EMAIL HERE>, pass: <MY APPS PASSWORD HERE>, }, }); exports.sendMeetingNotification = functions.firestore .document("meeting_requests/{docId}") .onCreate(async (snap, context) => { const data = snap.data(); const receiverId = data.receiverId; console.log("Fetching user data for receiverId:", receiverId); try { const userDoc = await admin.firestore().collection("users").doc(receiverId).get(); if (!userDoc.exists) { console.log("No user found with the given receiverId:", receiverId); return; } const email = userDoc.data().email; console.log("Found user with email:", email); const mailOptions = { from: "\"ConnectEd\" connected.app.contact@gmail.com", to: email, subject: "New Meeting Request from Teacher", html: ` <div style="background-color: #f9f7cf; padding: 20px; font-family: Arial, sans-serif; color: #333;""> <div style="text-align: center; margin-bottom: 20px;""> <img src="https://your-logo-url.com/logo.png" alt="ConnectEd Logo" style="width: 100px; height: auto;" /> </div> <div style="background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"> <h2 style="color: #2c3e50; ">New Meeting Request from ${data.senderName}</h2> <p style="font-size: 16px; line-height: 1.6;"> <strong>Note from teacher:</strong> ${data.note} </p> <p style="font-size: 16px; line-height: 1.6;"> Please click the link below to view the request: </p> <div style="text-align: center; margin: 20px 0;"> <a href="yourapp://app/openRequest?requestId=${context.params.docId}" style="background-color: #f39c12; color: #fff; padding: 10px 20px; text-decoration: none; border-radius: 5px; font-size: 16px;">View Request</a> </div> </div> <div style="text-align: center; margin-top: 20px; font-size: 12px; color: #999;"> <p>© 2024 ConnectEd. All rights reserved.</p> <p>If you did not request this email, please ignore it.</p> </div> </div> `, }; console.log("Sending email to:", email); await transporter.sendMail(mailOptions); console.log("Email sent successfully to:", email); } catch (error) { console.error("Error sending email notification:", error); } });
但运行时邮件未发送,且日志中出现以下错误:
2024-09-07T14:37:34.038106Z ? sendMeetingNotification: Error sending email notification: Error: 7 PERMISSION_DENIED: Missing or insufficient permissions. 2024-09-07T14:37:34.038127Z ? sendMeetingNotification: at callErrorFromStatus (/workspace/node_modules/@grpc/grpc-js/build/src/call.js:31:19) 2024-09-07T14:37:34.038251Z ? sendMeetingNotification: code: 7, 2024-09-07T14:37:34.038256Z ? sendMeetingNotification: details: 'Missing or insufficient permissions.', s.', 2024-09-07T14:37:34.038261Z ? sendMeetingNotification: metadata: Metadata { 2024-09-07T14:37:34.038266Z ? sendMeetingNotification: internalRepr: Map(1) { 'x-debug-tracking-id' => [Array] }, d' => [Array] }, 2024-09-07T14:37:34.038270Z ? sendMeetingNotification: options: {} 2024-09-07T14:37:34.038274Z ? sendMeetingNotification: } 2024-09-07T14:37:34.038274Z ? sendMeetingNotification: } 2024-09-07T14:37:34.038279Z ? sendMeetingNotification: } 2024-09-07T14:37:34.039269068Z D sendMeetingNotification: Function execution took 54 ms, finished with status: 'ok'
昨天还能正常运行,今天突然失效,尝试调整Firebase权限、添加Gmail账号到云权限均无效,需要协助解决。
解决方案
检查Cloud Functions服务账号的Firestore权限
Cloud Functions默认使用[你的项目ID]@appspot.gserviceaccount.com这个服务账号执行。登录Google Cloud控制台的IAM页面,找到该账号,确保它拥有Cloud Datastore User角色(或更细粒度的roles/datastore.reader角色),这样才能读取users集合中的文档。验证Gmail应用密码的有效性
- 确认你的Google账号已开启两步验证,应用密码仅对开启2FA的账号有效。
- 检查应用密码是否正确,若最近重置过账号密码或重新生成过应用密码,需更新代码中的
pass字段。 - 登录Google账号的安全设置页面,确认没有禁用应用密码的相关权限。
调整Firestore安全规则
确保Firestore规则允许服务账号访问users集合,修改规则如下:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { // 允许认证用户或服务账号读取 allow read: if request.auth != null || request.serviceAccount; // 其他写入规则根据你的需求设置 allow write: if request.auth.uid == userId; } match /meeting_requests/{docId} { allow create: if request.auth != null; } } }修复代码中的HTML语法错误
代码中的HTML模板存在多余的"转义字符,会导致HTML渲染异常,同时可能影响邮件发送的完整性。修正后的HTML部分如下:const mailOptions = { from: "\"ConnectEd\" connected.app.contact@gmail.com", to: email, subject: "New Meeting Request from Teacher", html: ` <div style="background-color: #f9f7cf; padding: 20px; font-family: Arial, sans-serif; color: #333;"> <div style="text-align: center; margin-bottom: 20px;"> <img src="https://your-logo-url.com/logo.png" alt="ConnectEd Logo" style="width: 100px; height: auto;" /> </div> <div style="background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);"> <h2 style="color: #2c3e50;">New Meeting Request from ${data.senderName}</h2> <p style="font-size: 16px; line-height: 1.6;"> <strong>Note from teacher:</strong> ${data.note} </p> <p style="font-size: 16px; line-height: 1.6;"> Please click the link below to view the request: </p> <div style="text-align: center; margin: 20px 0;"> <a href="yourapp://app/openRequest?requestId=${context.params.docId}" style="background-color: #f39c12; color: #fff; padding: 10px 20px; text-decoration: none; border-radius: 5px; font-size: 16px;">View Request</a> </div> </div> <div style="text-align: center; margin-top: 20px; font-size: 12px; color: #999;"> <p>© 2024 ConnectEd. All rights reserved.</p> <p>If you did not request this email, please ignore it.</p> </div> </div> `, };
内容的提问来源于stack exchange,提问作者SwimmerSat
相关产品推荐
相关产品推荐

