使用Python email模块处理邮件时遇int类型错误问题求助
问题分析与解决方案
问题根源
- 邮件ID失效:循环内执行
server.expunge()会触发邮箱邮件重新编号,你提前获取的未读邮件ID列表(msg_list)在expunge后已经失效,用旧ID调用fetch会得到错误响应,而非目标邮件内容。 - 错误处理fetch结果:
imaplib.fetch()返回的data中可能混有状态响应(字节串格式),直接取data[0][1]会在非邮件内容项时得到字节的ASCII数值(比如b'62 (...)'[1]对应字符'2'的ASCII码50),导致email_body变成int类型,触发decode属性错误。
修正后的代码
import imaplib import email import os download_folder = "/Users/zonghan/Desktop" def get_mail(username, password): server = imaplib.IMAP4_SSL('imap.gmail.com') server.login(username, password) # 可读写模式打开收件箱,若仅测试可改为readonly=True避免误操作 server.select("INBOX", readonly=False) email_type, items = server.search(None, "UNSEEN") msg_list = items[0].split() for email_id in msg_list: print(f'id:{email_id}') email_type, data = server.fetch(email_id, "(RFC822)") # 过滤出真正的邮件内容元组 email_body = None for item in data: if isinstance(item, tuple): email_body = item[1] break if not email_body: print(f"无法获取邮件 {email_id} 的内容") continue print(email_body[:100], type(email_body)) # 仅打印前100字节避免输出过长 mail = email.message_from_bytes(email_body) # 标记邮件为已读 server.store(email_id, '+FLAGS', '\\Seen') # 处理邮件附件逻辑 for part in mail.walk(): # 跳过多部分容器 if part.get_content_maintype() == 'multipart': continue # 跳过无附件标识的部分 if part.get('Content-Disposition') is None: continue filename = part.get_filename() if not filename: continue # 保存附件到指定目录 filepath = os.path.join(download_folder, filename) with open(filepath, 'wb') as f: f.write(part.get_payload(decode=True)) print(f"附件 {filename} 已保存到 {filepath}") # 所有邮件处理完成后再执行expunge(仅当需要删除已标记为删除的邮件时保留,否则可删除) # server.expunge() server.close() server.logout()
关键修改点
- 将
server.expunge()移到循环结束后,避免中途打乱邮件ID序列;若无需删除邮件,可直接移除该语句。 - 遍历
fetch返回的data集合,仅处理元组类型元素,确保拿到正确的邮件字节内容。 - 补充完整的附件下载逻辑(原代码仅跳过了多部分容器,未实现附件保存)。
- 增加
server.close()和server.logout(),规范关闭IMAP连接。
额外提示
- 若Gmail账号开启了两步验证,需使用应用专用密码登录;未开启的话需允许"不太安全的应用访问"(或在Google账号设置中调整IMAP权限)。
- 测试阶段建议用
readonly=True打开收件箱,避免误修改邮件状态。
内容的提问来源于stack exchange,提问作者hans
相关产品推荐
相关产品推荐

