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

如何通过Gmail API高效获取邮箱地址以统计高频收发件人?

问题:如何高效批量获取Gmail邮件的收件人/发件人以统计高频邮箱?

我现在需要统计用户邮箱的高频发件人与收件人,原本的计划是获取所有用户邮箱地址存入字典计数后输出,但当前代码处理包含10000+邮件的INBOX标签时表现极差——每次循环都要单独发起API请求,速度慢得难以接受。

我的现有代码如下:

import base64
import email
import re
import operator
from googleapiclient import errors
from quickstart import service

def find(st):
    for i in range(0,len(st)):
        tmp = str(st[i])
        for j in range(0,len(tmp)):
            if tmp[j] == 'T' and tmp[j+1] == 'o' and tmp[j-1] == "'" and tmp[j+2] == "'":
                return i
    pass

def getTop(n):
    try:
        if n == 1:
            label_ids = "INBOX"
        else:
            label_ids = "SENT"
        user_id = "me"
        topers = service.users().labels().get(userId = user_id,id = label_ids).execute()
        count = topers['messagesTotal']
        print(count)
        topers = service.users().messages().list(userId = user_id, labelIds = label_ids).execute()
        arrId = []
        for i in range(0,count):
            arrId.append(topers['messages'][i]['id'])
        st = []
        for i in range(0,count):
            message = service.users().messages().get(userId=user_id, id=arrId[i], format = 'metadata').execute()
            head = message['payload']['headers']
            index = find(head)
            obval = head[index]['value']
            tmp = str(obval)
            tmp =tmp.split('<', 1)[-1]
            tmp = tmp.replace('>',"")
            st.append(tmp)
        cnt = 0
        mvalues = {}
        for mail in st:
            if not mail in mvalues:
                mvalues[mail] = 1
            else:
                mvalues[mail]+= 1
        sorted_values = sorted(mvalues.items(),key= operator.itemgetter(1))
        ln = len(sorted_values)
        for j in range(1,6):
            print(sorted_values[-j])
        pass
    except errors.HttpError as error:
        print('An error occurred: %s' % error)

请问在邮件数量较多时,无需每次循环发起请求,最快且最准确的批量获取用户邮箱地址的方法是什么?已经被这个问题困扰4天了,恳请大家帮忙!


回答

嘿,我之前也踩过Gmail API批量请求的坑,针对你遇到的10000+邮件性能问题,给你一套实打实的优化方案,能直接解决你的困扰:

核心优化思路:减少API请求次数 + 精准获取所需数据

1. 用batchGet批量获取邮件,替代循环单请求

Gmail API提供了users.messages.batchGet接口,允许你一次性传入最多100个邮件ID,这能把10000次请求压缩到100次左右,直接砍掉99%的网络开销,速度提升非常明显。

同时,我们可以通过metadataHeaders参数只请求我们需要的To或From字段,减少不必要的数据传输,进一步提升效率。

2. 修复邮件ID获取的分页问题

你当前的messages.list调用只获取了第一页的邮件ID(默认最多100条),完全漏掉了后面的邮件!必须通过pageToken处理分页才能拿到所有邮件ID。

3. 替换低效且易出错的find函数

原来的find函数通过字符串匹配找头部字段的方式非常脆弱,直接遍历headers的name字段匹配要高效准确得多。


优化后的完整代码片段

import re
import operator
from googleapiclient import errors
from quickstart import service

def get_top_contacts(n):
    try:
        label_ids = "INBOX" if n == 1 else "SENT"
        user_id = "me"
        
        # 第一步:分页获取所有邮件ID(修复原代码的分页问题)
        arr_id = []
        page_token = None
        max_results_per_page = 500  # 每页最多取500条,减少请求次数
        while True:
            response = service.users().messages().list(
                userId=user_id,
                labelIds=label_ids,
                pageToken=page_token,
                maxResults=max_results_per_page
            ).execute()
            messages = response.get('messages', [])
            arr_id.extend([msg['id'] for msg in messages])
            
            page_token = response.get('nextPageToken')
            if not page_token:
                break
        
        print(f"总共获取到 {len(arr_id)} 封邮件ID")
        
        # 第二步:批量获取邮件的目标头部字段(To/From)
        st = []
        batch_size = 100  # Gmail batchGet最多支持100个ID
        target_header = 'To' if label_ids == 'INBOX' else 'From'
        
        for i in range(0, len(arr_id), batch_size):
            batch_ids = arr_id[i:i+batch_size]
            # 批量请求,只获取需要的头部字段
            batch_response = service.users().messages().batchGet(
                userId=user_id,
                ids=batch_ids,
                format='metadata',
                metadataHeaders=[target_header]
            ).execute()
            
            # 处理批量返回的结果
            for msg in batch_response.get('messages', []):
                headers = msg['payload']['headers']
                for h in headers:
                    if h['name'] == target_header:
                        # 提取邮箱地址(兼容带姓名的格式,比如"张三 <zhangsan@example.com>")
                        match = re.search(r'<([^>]+)>', h['value'])
                        if match:
                            email_addr = match.group(1)
                            st.append(email_addr)
                        # 处理纯邮箱地址的情况(没有<>包裹)
                        else:
                            st.append(h['value'].strip())
                        break
        
        # 第三步:统计高频邮箱(原代码的计数逻辑保留,稍微优化写法)
        contact_count = {}
        for mail in st:
            contact_count[mail] = contact_count.get(mail, 0) + 1
        
        # 按次数降序排序,取前5个
        sorted_contacts = sorted(contact_count.items(), key=operator.itemgetter(1), reverse=True)
        print("Top 5 高频联系人:")
        for idx, (email, count) in enumerate(sorted_contacts[:5], 1):
            print(f"{idx}. {email}: {count} 次")
            
    except errors.HttpError as error:
        print('An error occurred: %s' % error)

# 调用示例:1=统计收件人,2=统计发件人
get_top_contacts(1)

额外优化建议(可选)

  • 如果性能要求极高,可以结合异步请求(比如用aiohttp或Google API的异步客户端)并行发起多个batch请求,但这需要调整代码结构,适合超大量邮件的场景。
  • 可以考虑加入缓存机制,如果不需要实时统计,定期缓存统计结果,避免重复请求API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:48:36