如何使用Python2.7读取Gmail邮件正文并下载附件?
搞定邮件附件下载:从问题排查到代码修复
我太懂这种感觉了——能顺利读出邮件正文,偏偏卡在附件下载这一步,还碰到消息类型的小坑,确实让人头疼。咱们一步步来拆解,先把附件下载的核心逻辑捋顺,再解决消息类型的疑问。
一、先把附件下载的核心逻辑补全
邮件的结构其实是MIME多部分(Multipart)嵌套的,附件一般藏在子部分里,关键是要准确识别出哪些部分是附件。这里给你一个基于Python imaplib和email库的修复示例,你可以对照自己的代码调整:
import imaplib import email from email.policy import default from email.header import decode_header # 连接IMAP邮箱(替换成你的邮箱服务器地址) mail = imaplib.IMAP4_SSL('imap.yourmail.com') mail.login('your_email@example.com', 'your_auth_code') # 注意:有些邮箱需要用授权码而非密码 mail.select('inbox') # 搜索目标邮件(这里以所有邮件为例,你可以改成已读/未读等条件) status, message_ids = mail.search(None, 'ALL') for msg_id in message_ids[0].split(): # 获取原始邮件内容 status, raw_msg = mail.fetch(msg_id, '(RFC822)') msg = email.message_from_bytes(raw_msg[0][1], policy=default) # 遍历邮件的所有MIME部分 for part in msg.walk(): # 跳过正文部分(纯文本/HTML) if part.get_content_type() in ['text/plain', 'text/html']: continue # 判断是否为附件:检查Content-Disposition或是否有文件名 content_dispo = part.get("Content-Disposition", "") filename = part.get_filename() if ("attachment" in content_dispo) or (filename is not None and filename != ""): # 解码文件名(处理中文/特殊字符编码) if filename: decoded_name = decode_header(filename)[0][0] if isinstance(decoded_name, bytes): decoded_name = decoded_name.decode('utf-8') # 写入附件到本地 with open(decoded_name, 'wb') as f: f.write(part.get_payload(decode=True)) print(f"✅ 成功下载附件: {decoded_name}")
关键要点解释:
msg.walk():能遍历所有嵌套的MIME部分,不管邮件是单层还是多层嵌套结构,都不会漏掉附件- 附件判断逻辑:同时检查
Content-Disposition(是否包含attachment)和文件名,避免漏掉那些没明确标记但有文件名的附件 - 文件名解码:用
decode_header()处理中文或特殊字符的文件名,避免出现乱码
二、聊聊邮件消息类型的坑
你提到无附件邮件的消息类型有疑问,这里给你梳理常见类型:
- 纯文本无附件:
text/plain(单部分结构,非Multipart) - HTML正文无附件:要么是
text/html单部分,要么是multipart/alternative(同时包含纯文本和HTML两个子部分) - 带附件的邮件:基本都是
multipart/mixed,正文和附件作为独立子部分存在 - 带嵌入资源(比如签名图片)的邮件:会用
multipart/related,这类资源可以通过Content-ID区分——如果part.get('Content-ID')不为空,大概率是嵌入资源,不是需要下载的附件,可以跳过
如果你不确定当前处理的邮件类型,建议在代码里加一行打印:
print(f"当前邮件类型: {msg.get_content_type()}")
这样就能针对性调整处理逻辑。
三、容易踩的小坑提醒
- 授权码问题:现在很多邮箱(比如QQ、网易)禁用了直接用密码登录IMAP,需要在邮箱设置里开启IMAP服务并生成授权码
- 超大附件:如果遇到几百MB的大附件,直接
get_payload(decode=True)会占用大量内存,可以改成分块写入 - 服务器限制:部分IMAP服务器会限制单次获取的邮件大小,这时候可以用
BODY.PEEK[]分部分获取附件内容
如果你的代码还有具体的报错或者逻辑问题,把代码贴出来咱们可以精准定位!
内容的提问来源于stack exchange,提问作者Krakenudo
相关产品推荐
相关产品推荐

