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

如何用UserScript可靠提取Gmail中隐藏的详细邮件头?

问题

我正在开发一款用于Gmail的UserScript,目标是复制完整的邮件详情,包括完整邮件头信息(发件人、所有收件人、日期、Message-ID、'mailed-by'、'signed-by'等)。这些邮件头默认处于折叠状态,需点击"Show details"按钮才能显示,不确定是否存储在DOM其他位置。

核心挑战

  • 数据源位置不明确:不清楚完整邮件头是仅存在于点击展开后的DOM中,还是有更直接的访问方式
  • UI元素识别与触发:需要可靠定位并自动触发"Show details"按钮
  • 异步DOM更新处理:点击后需等待Gmail异步渲染完展开的邮件头再提取数据
  • 数据提取稳定性:要从结构多变的DOM或其他数据源中持续提取指定字段

可靠解决方案

方法一:通过UI交互提取(兼容大多数场景)

这种方法模拟用户操作展开邮件头再提取数据,逻辑直观,适配Gmail的UI迭代更新:

  1. 定位并触发"Show details"按钮
    优先通过文本匹配定位按钮,避免依赖易变的类名:

    // 适配多语言环境的按钮定位
    const targetTexts = ['Show details', '显示详情', '詳細を表示'];
    const showDetailsBtn = Array.from(document.querySelectorAll('div[role="button"]')).find(btn => 
      targetTexts.includes(btn.textContent.trim())
    );
    
    if (showDetailsBtn && !showDetailsBtn.disabled) {
      showDetailsBtn.click();
    }
    
  2. 等待邮件头DOM加载完成
    用MutationObserver监听DOM变化,直到目标邮件头容器出现:

    function waitForHeaderElement(selector, timeout = 10000) {
      return new Promise((resolve, reject) => {
        const observer = new MutationObserver((mutations) => {
          const element = document.querySelector(selector);
          if (element) {
            observer.disconnect();
            resolve(element);
          }
        });
        observer.observe(document.body, { childList: true, subtree: true });
        setTimeout(() => {
          observer.disconnect();
          reject(new Error('等待邮件头超时'));
        }, timeout);
      });
    }
    
    // 调用:监听包含Message-ID的区域或已知的邮件头容器类
    waitForHeaderElement('div.ii.gt, div:has-text("Message-ID")').then(headerContainer => {
      // 执行数据提取逻辑
    });
    
  3. 提取指定邮件头字段
    从展开的容器中解析字段,单独处理特殊的认证信息:

    function extractHeaders(headerContainer) {
      const headers = {};
      // 拆分邮件头文本行并提取键值对
      const lines = headerContainer.textContent.split('\n')
        .map(line => line.trim())
        .filter(line => line.includes(':'));
    
      lines.forEach(line => {
        const [key, ...valueParts] = line.split(':');
        headers[key.trim()] = valueParts.join(':').trim();
      });
    
      // 提取mailed-by/signed-by(通常在邮件头下方的小字体区域)
      const authElements = document.querySelectorAll('span.gD, span.gE');
      authElements.forEach(el => {
        const text = el.textContent.trim();
        if (text.includes('mailed-by:')) headers['mailed-by'] = text.split('mailed-by:')[1].trim();
        if (text.includes('signed-by:')) headers['signed-by'] = text.split('signed-by:')[1].trim();
      });
    
      return headers;
    }
    

方法二:直接访问Gmail内部数据(高效但需适配)

Gmail会在页面全局对象中存储完整邮件数据,无需操作UI即可直接获取:

  1. 定位当前邮件的原始数据
    先获取当前邮件ID,再从全局存储中匹配对应数据:

    // 获取当前打开邮件的ID
    const currentEmailId = document.querySelector('[data-legacy-message-id]')?.getAttribute('data-legacy-message-id');
    let emailData = null;
    
    // 适配不同Gmail版本的全局数据位置
    if (window.gmail?.data?.messages) {
      emailData = Object.values(window.gmail.data.messages).find(msg => msg.id === currentEmailId);
    } else if (window._GM_?.mail?.currentMessage) {
      emailData = window._GM_.mail.currentMessage;
    }
    
  2. 从原始数据中提取邮件头
    原始邮件头通常在payload.headers字段中,认证信息在payload.policy:

    if (emailData?.payload?.headers) {
      const headers = {};
      emailData.payload.headers.forEach(header => {
        headers[header.name] = header.value;
      });
    
      // 补充认证信息
      if (emailData.payload.policy) {
        headers['mailed-by'] = emailData.payload.policy.mailedBy;
        headers['signed-by'] = emailData.payload.policy.signedBy;
      }
    
      console.log('提取到的完整邮件头:', headers);
    }
    

关键注意事项

  • 版本兼容性:全局对象结构可能随Gmail更新变化,建议保留两种方法作为 fallback
  • 权限保障:UserScript默认拥有页面全局变量访问权限,无需额外配置
  • 稳定性优先:若直接访问失败,自动切换到UI交互方法,确保功能可用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:53:17