You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Firebase Functions结合Gmail API从Google Workspace发邮件?

如何通过Firebase Cloud Function结合Google Workspace账号发送邮件?

背景需求

我需要创建一个名为sendEmail的Firebase云函数,用于通过Google Workspace邮箱发送邮件,React前端通过以下代码调用:

const sendEmailFn = httpsCallable(functions, 'sendEmail');
const response = await sendEmailFn({ email, subject, message });

最初实现与报错

初始云函数代码

const functions = require("firebase-functions");
const {google} = require("googleapis");

const oAuth2Client = new google.auth.OAuth2(
    process.env.CLIENT_ID,
    process.env.CLIENT_SECRET,
    process.env.CALLBACK_URL,
);

const gmailClient = new google.gmail({
  version: "v1",
  auth: oAuth2Client,
});

exports.sendEmail = functions.https.onCall(async (data, context) => {
  const {email, subject, message} = data;

  const emailContent = `
    From: "Sender Name" <email@example.com>
    To: "Recipient Name" <${email}>
    Subject: ${subject}
    Content-Type: text/html; charset=utf-8

    ${message}
  `;

  try {
    await gmailClient.users.messages.send({
      userId: "me",
      requestBody: {
        raw: Buffer.from(emailContent).toString("base64"),
      },
    });
    return {success: true};
  } catch (error) {
    console.error("Error sending email:", error);
    throw new functions.https.HttpsError(
        "internal",
        "An error occurred while sending the email.",
    );
  }
});

遇到的错误

  1. 调用时日志报错:

I still get Error sending email: Error: No access, refresh token, API key or refresh handler callback is set.

  1. 尝试将API Key设为access_token后:

message: 'Invalid Credentials'

  1. 直接在gmail.auth中设置API Key,请求返回401 Response,且Gmail API仅支持OAuth2客户端ID和服务账号,无法用普通API Key认证。

尝试服务账号后的新问题

改用服务账号认证后,代码如下:

// Create an OAuth2 client using the service account credentials
const authClient = new google.auth.JWT({
  email: keyFile.client_email,
  key: keyFile.private_key,
  scopes: ["https://www.googleapis.com/auth/gmail.send", "https://www.googleapis.com/auth/gmail.readonly"],
});

authClient.authorize((err, tokens) => {
  if (err) {
    console.error("Error authenticating:", err);
    throw new Error("Failed to authenticate");
  } else {
    console.log("Authentication successful");
  }
});

认证成功,但发送邮件时出现:

Code: 400, message: 'Precondition check failed.'

修改userId: "me"参数也无法解决问题。


正确解决方案

1. 完成服务账号与域范围委派配置

  • 在Google云控制台创建服务账号,下载JSON格式的密钥文件
  • 以Google Workspace管理员身份,在Admin控制台为该服务账号启用域范围委派,添加授权范围:https://www.googleapis.com/auth/gmail.send
  • 这一步是核心:没有域范围委派,服务账号无法模拟Workspace用户发送邮件

2. 修正后的云函数代码

const functions = require("firebase-functions");
const { google } = require("googleapis");
// 建议用Firebase环境变量存储密钥,避免硬编码
const serviceAccount = JSON.parse(functions.config().service_account.key);
const senderEmail = "your-workspace-email@example.com"; // 指定发件人邮箱

exports.sendEmail = functions.https.onCall(async (data, context) => {
  const { email, subject, message, recipientName = "Recipient" } = data;

  // 初始化JWT客户端,指定要模拟的Workspace用户
  const authClient = new google.auth.JWT({
    email: serviceAccount.client_email,
    key: serviceAccount.private_key,
    scopes: ["https://www.googleapis.com/auth/gmail.send"],
    subject: senderEmail, // 关键:指定要模拟的发件人邮箱
  });

  const gmailClient = google.gmail({ version: "v1", auth: authClient });

  // 构造符合RFC 2822标准的邮件内容
  const emailContent = [
    `From: "Sender Name" <${senderEmail}>`,
    `To: "${recipientName}" <${email}>`,
    `Subject: ${subject}`,
    "Content-Type: text/html; charset=utf-8",
    "", // 空行分隔邮件头部与正文
    message,
  ].join("\n");

  // 转换为Gmail API要求的URL安全Base64编码
  const raw = Buffer.from(emailContent)
    .toString("base64")
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");

  try {
    await gmailClient.users.messages.send({
      userId: senderEmail, // 用具体发件人邮箱替代"me"
      requestBody: { raw },
    });
    return { success: true };
  } catch (error) {
    console.error("邮件发送失败:", error);
    throw new functions.https.HttpsError(
      "internal",
      "邮件发送过程中出现错误。"
    );
  }
});

3. 关键注意事项

  • 域范围委派:必须由Workspace管理员操作,否则服务账号无法获得模拟用户的权限
  • 邮件格式:严格遵循RFC 2822规范,头部与正文之间必须有空行
  • Base64编码:Gmail API要求raw字段为URL安全的Base64,需替换+、/、=字符
  • userId参数:不能使用"me",必须指定具体的发件人邮箱(与subject参数一致)
  • 密钥安全:不要将服务账号密钥硬编码到代码中,使用Firebase环境变量存储:
    firebase functions:config:set service_account.key="$(cat service-account-key.json)"
    

错误原因总结

  1. 初始OAuth2客户端错误:缺少有效的access/refresh token,普通OAuth2流程需要用户授权,不适合无交互的云函数场景
  2. API Key无效:Gmail发送邮件接口不支持API Key认证,仅支持OAuth2或服务账号
  3. 服务账号400错误:未启用域范围委派,或未指定要模拟的Workspace用户(subject参数缺失),导致无法代表用户发送邮件

内容的提问来源于stack exchange,提问作者kaiserm99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:07:11