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

使用Python调用Gmail API下载受密码保护附件时无法识别文件的问题求助

解决Gmail API无法识别受密码保护附件的问题

我之前也碰到过一模一样的情况!问题根源在于受密码保护的PDF/Excel这类附件,通常会被封装在嵌套的MIME部分里,而不是作为顶级的附件part存在。你当前的代码只遍历了最外层的parts,自然找不到藏在深层的加密文件。

为什么会出现这个问题?

当发送方发送带密码保护的文件时,不少邮件系统会把加密文件打包进multipart/encrypted或者application/pkcs7-mime类型的MIME容器中——这个容器本身不是附件,但真正的加密文件是它的子part。你的代码只检查了顶级part的filename字段,所以直接漏掉了这些嵌套内容。

解决方案:递归遍历所有MIME层级

不管用原生Gmail API还是ezgmail,都需要递归遍历所有层级的MIME parts,才能揪出藏在深层的加密附件。

1. 原生Gmail API的修改版代码

我给你写了个递归函数来遍历所有parts,替换你原来的遍历逻辑就行:

def find_all_attachments(payload):
    attachments = []
    
    # 如果当前payload包含子part,递归遍历
    if 'parts' in payload:
        for part in payload['parts']:
            attachments.extend(find_all_attachments(part))
    else:
        # 判断当前part是否为附件:有文件名,或是常见的加密文件类型
        filename = payload.get('filename')
        target_types = [
            'application/pdf',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'application/vnd.ms-excel',
            'application/octet-stream'
        ]
        if filename or (payload.get('mimeType') in target_types):
            attachments.append(payload)
    
    return attachments

# 替换原代码的遍历逻辑
for message in messages:
    msg = service.users().messages().get(userId='me', id=message['id']).execute()
    payload = msg['payload']
    all_attachments = find_all_attachments(payload)
    
    for att in all_attachments:
        # 给无文件名的加密文件默认命名
        filename = att.get('filename') or f"encrypted_file.{att['mimeType'].split('/')[-1]}"
        print(f"找到附件: {filename}")
        
        # 处理附件下载
        if 'data' in att['body']:
            data = att['body']['data']
        else:
            att_id = att['body']['attachmentId']
            att_data = service.users().messages().attachments().get(
                userId='me', messageId=message['id'], id=att_id
            ).execute()
            data = att_data['data']
        
        # 可选:base64解码并保存文件
        # import base64
        # decoded_data = base64.urlsafe_b64decode(data)
        # with open(filename, 'wb') as f:
        #     f.write(decoded_data)

2. ezgmail的处理方式

ezgmail的message.attachments只返回顶级附件,所以得拿到原始的Gmail API消息payload来递归处理:

import ezgmail

threads = ezgmail.search('LABEL:'+bank)
for thread in threads:
    for message in thread.messages:
        # 获取ezgmail封装的原始API消息对象
        raw_msg = message.msg
        all_attachments = find_all_attachments(raw_msg['payload'])
        
        for att in all_attachments:
            filename = att.get('filename') or f"encrypted_file.{att['mimeType'].split('/')[-1]}"
            print(f"找到附件: {filename}")
            # 后续下载逻辑和上面的原生API代码一致

额外小提示

  • 有些加密附件的MIME类型会是application/octet-stream(二进制流),记得把这个类型加入判断列表。
  • 如果遇到filename为空的情况,可以根据MIME类型自动生成文件名,避免出现无意义的文件名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:32:30