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

如何在Node.js中通过Google API获取并格式化Gmail邮件?

问题:如何渲染与Gmail一致格式的邮件内容?

我正在使用Node.js中的Google API库获取Gmail邮件,以下代码片段展示了我如何检索并提取邮件数据:

const gmail = google.gmail({ version: "v1", auth: oAuth2Client });
const messageId = req.params.id;

const message = await gmail.users.messages.get({
  userId: "me",
  id: messageId,
  format: "full",
});

// Extract the required data from the message
const isRead = !message.data.labelIds.includes("UNREAD");
const snippet = message.data.snippet.trim();
const email = {
  id: message.data.id,
  subject: message.data.payload.headers.find(
    (header) => header.name === "Subject"
  ).value,
  from: message.data.payload.headers
    .find((header) => header.name === "From")
    .value.split("<")[0],
  date: moment(
    message.data.payload.headers.find((header) => header.name === "Date").value
  ).format("MM/DD/YYYY, hh:mm a"),
  snippet,
  isRead,
  message: Buffer.from(message.data.payload.parts[0].body.data,
          "base64").toString("utf-8"),
};

上述代码可成功获取邮件并提取主题、发件人、日期及邮件内容等关键信息,但提取出的message为原始格式,无法保留Gmail界面中的原有排版与格式。我希望能实现与Gmail网页端或官方App一致的邮件渲染效果,请问该如何对获取到的邮件进行格式化处理?


解决思路与改进方案

1. 优先获取HTML格式的邮件内容

Gmail邮件通常以multipart/alternative格式存在,同时包含纯文本(text/plain)和富文本(text/html)版本。需要递归遍历邮件的parts结构,找到text/html类型的内容部分,解码其Base64数据后即可得到带排版格式的HTML内容。

2. 处理内嵌资源(如图片)

邮件中的内嵌图片通常使用cid:协议引用附件,需要将这些CID替换为对应的Base64 Data URI,这样HTML才能直接渲染图片。

3. 安全净化HTML内容

直接渲染外部邮件的HTML存在XSS攻击风险,必须使用HTML净化库(如DOMPurify)过滤掉不安全的标签和脚本。


改进后的代码示例

const gmail = google.gmail({ version: "v1", auth: oAuth2Client });
const messageId = req.params.id;
const DOMPurify = require('dompurify');
const { JSDOM } = require('jsdom');
const moment = require('moment');

// 初始化DOMPurify用于HTML净化
const window = new JSDOM('').window;
const purify = DOMPurify(window);

const message = await gmail.users.messages.get({
  userId: "me",
  id: messageId,
  format: "full",
});

// 封装获取Header的工具函数,避免重复代码
const getHeaderValue = (headerName) => {
  const header = message.data.payload.headers.find(h => h.name === headerName);
  return header?.value || '';
};

// 提取基础邮件信息
const isRead = !message.data.labelIds.includes("UNREAD");
const snippet = message.data.snippet.trim();
const email = {
  id: message.data.id,
  subject: getHeaderValue('Subject'),
  from: getHeaderValue('From').split("<")[0],
  date: moment(getHeaderValue('Date')).format("MM/DD/YYYY, hh:mm a"),
  snippet,
  isRead,
  plainTextMessage: '', // 纯文本内容(备用)
  formattedHtmlMessage: '' // 带格式的HTML内容
};

// 递归查找指定MIME类型的邮件部分
const findMessagePart = (parts, targetMimeType) => {
  for (const part of parts) {
    if (part.mimeType === targetMimeType) {
      return part;
    }
    // 处理嵌套的parts结构
    if (part.parts && part.parts.length > 0) {
      const nestedPart = findMessagePart(part.parts, targetMimeType);
      if (nestedPart) return nestedPart;
    }
  }
  return null;
};

// 处理HTML内容
const htmlPart = findMessagePart([message.data.payload], 'text/html');
if (htmlPart) {
  let htmlContent = Buffer.from(htmlPart.body.data, 'base64').toString('utf-8');
  
  // 替换内嵌图片的CID引用为Data URI
  const attachments = message.data.payload.parts?.filter(part => 
    part.filename && part.body?.attachmentId && part.headers?.some(h => h.name === 'Content-ID')
  ) || [];
  
  attachments.forEach(attachment => {
    const cidHeader = attachment.headers.find(h => h.name === 'Content-ID');
    const cid = cidHeader.value.replace(/[<>]/g, ''); // 去掉CID的<>包裹
    const attachmentBase64 = Buffer.from(attachment.body.data, 'base64').toString('base64');
    htmlContent = htmlContent.replace(
      `cid:${cid}`, 
      `data:${attachment.mimeType};base64,${attachmentBase64}`
    );
  });
  
  // 净化HTML,防止XSS攻击
  email.formattedHtmlMessage = purify.sanitize(htmlContent);
}

// 处理纯文本内容(作为HTML内容的降级备选)
const textPart = findMessagePart([message.data.payload], 'text/plain');
if (textPart) {
  email.plainTextMessage = Buffer.from(textPart.body.data, 'base64').toString('utf-8');
}

关键说明

  • 递归查找邮件部分:邮件结构可能嵌套多层(比如multipart/related包含HTML和附件),递归遍历能确保找到目标MIME类型的内容。
  • CID图片处理:将邮件附件转成Data URI嵌入HTML,无需额外请求即可渲染图片。
  • HTML净化:DOMPurify会过滤掉<script>、<iframe>等危险标签,保证渲染安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:46:05