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

如何通过Google Drive文件ID在Node.js中创建带附件的Gmail草稿

使用Gmail API和Drive API在Node.js中通过fileId创建带附件的邮件草稿(无需下载文件)

核心思路

Gmail API创建草稿需要Base64编码的原始MIME消息,要直接引用Drive文件作为附件且不落地本地文件,关键是通过Drive API获取文件的二进制流,实时进行Base64编码后嵌入MIME结构,跳过本地文件下载步骤。

代码实现

假设你已完成Google OAuth2客户端初始化(需包含https://www.googleapis.com/auth/gmail.compose和https://www.googleapis.com/auth/drive.readonly权限),以下是完整实现:

1. 依赖准备

先安装Google官方客户端库:

npm install googleapis

2. 初始化客户端与Drive文件流获取

const { google } = require('googleapis');

// 替换为你的OAuth2配置
const oauth2Client = new google.auth.OAuth2(
  'YOUR_CLIENT_ID',
  'YOUR_CLIENT_SECRET',
  'YOUR_REDIRECT_URI'
);
// 配置已获取的有效access_token(从认证流程或缓存中获取)
oauth2Client.setCredentials({ access_token: 'YOUR_ACCESS_TOKEN' });

const drive = google.drive({ version: 'v3', auth: oauth2Client });
const gmail = google.gmail({ version: 'v1', auth: oauth2Client });

/**
 * 获取Drive文件的元数据与二进制流
 * @param {string} fileId Drive文件ID
 * @returns {Promise<{name: string, mimeType: string, stream: Readable}>}
 */
async function getDriveFileStream(fileId) {
  // 获取文件名、MIME类型等元数据
  const fileMeta = await drive.files.get({
    fileId,
    fields: 'name, mimeType'
  });
  
  // 获取文件二进制流
  const fileStream = await drive.files.get({
    fileId,
    alt: 'media'
  }, { responseType: 'stream' });
  
  return {
    name: fileMeta.data.name,
    mimeType: fileMeta.data.mimeType,
    stream: fileStream.data
  };
}

3. 扩展createRawMessage函数,添加Drive附件

const { Transform } = require('stream');
const { Buffer } = require('buffer');

/**
 * 将二进制流直接转换为Base64字符串
 * @param {Readable} stream 文件流
 * @returns {Promise<string>}
 */
async function streamToBase64(stream) {
  return new Promise((resolve, reject) => {
    let base64Str = '';
    const transform = new Transform({
      transform(chunk, encoding, callback) {
        base64Str += chunk.toString('base64');
        callback();
      }
    });
    
    stream.pipe(transform);
    transform.on('end', () => resolve(base64Str));
    transform.on('error', reject);
  });
}

/**
 * 创建包含Drive附件的原始MIME消息
 * @param {string} to 收件人
 * @param {string} subject 邮件主题
 * @param {string} body 纯文本正文
 * @param {Array<string>} driveFileIds Drive文件ID列表
 * @returns {Promise<string>} URL安全的Base64编码消息
 */
async function createRawMessageWithDriveAttachments(to, subject, body, driveFileIds) {
  const boundary = `----GMAIL_BOUNDARY_${Date.now()}`;
  
  // 构建邮件基础部分
  let rawMessage = [
    `To: ${to}`,
    `Subject: ${subject}`,
    `MIME-Version: 1.0`,
    `Content-Type: multipart/mixed; boundary="${boundary}"`,
    '',
    `--${boundary}`,
    `Content-Type: text/plain; charset="UTF-8"`,
    '',
    body,
    ''
  ].join('\r\n');
  
  // 逐个处理Drive附件
  for (const fileId of driveFileIds) {
    const { name, mimeType, stream } = await getDriveFileStream(fileId);
    const base64Content = await streamToBase64(stream);
    
    rawMessage += [
      `--${boundary}`,
      `Content-Type: ${mimeType}`,
      `Content-Disposition: attachment; filename="${name}"`,
      `Content-Transfer-Encoding: base64`,
      '',
      base64Content,
      ''
    ].join('\r\n');
  }
  
  // 结束MIME边界
  rawMessage += `--${boundary}--`;
  
  // 转换为Gmail API要求的URL安全Base64编码
  return Buffer.from(rawMessage).toString('base64url');
}

4. 创建带附件的邮件草稿

/**
 * 创建包含Drive附件的邮件草稿
 * @param {string} userId 固定为'me'代表当前用户
 * @param {string} to 收件人邮箱
 * @param {string} subject 邮件主题
 * @param {string} body 邮件正文
 * @param {Array<string>} driveFileIds Drive文件ID列表
 */
async function createDraftWithDriveAttachments(userId, to, subject, body, driveFileIds) {
  const raw = await createRawMessageWithDriveAttachments(to, subject, body, driveFileIds);
  
  const response = await gmail.users.drafts.create({
    userId,
    requestBody: {
      message: {
        raw
      }
    }
  });
  
  console.log('草稿创建成功,ID:', response.data.id);
  return response.data;
}

// 调用示例
createDraftWithDriveAttachments(
  'me',
  'recipient@example.com',
  '带Drive附件的测试邮件',
  '这是一封包含Drive文件附件的邮件草稿',
  ['YOUR_DRIVE_FILE_ID']
).catch(err => console.error('创建草稿失败:', err));

关键说明

  • 无本地文件落地:通过Drive API流式获取文件内容,直接转换为Base64嵌入MIME消息,完全跳过本地文件存储步骤。
  • 权限要求:必须确保OAuth2客户端已申请gmail.compose(创建草稿权限)和drive.readonly(读取Drive文件权限),否则会触发权限错误。
  • MIME格式合规:严格按照RFC标准构建多部分MIME消息,兼容Gmail API的解析要求。

与Google Apps Script的差异

Apps Script中GmailApp.createDraft可以直接传入Drive文件对象,是因为Google内部封装了MIME消息构建和文件流处理逻辑。Node.js中需要手动构建MIME结构,但通过流式处理可以实现完全一致的“无需下载文件”效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:47:21