Python3.11+imaplib下载邮件遇编码错误,求解决方案
解决imaplib下载EML时的编码错误问题
错误原因分析
- UTF-8解码失败:邮件原始字节流的编码不一定是UTF-8,可能是GBK、ISO-8859-1等其他字符集,强行用UTF-8解码必然报错。
- charmap编码失败:用文本模式(
w)写入文件时,系统默认编码(如Windows的cp1252)不支持部分特殊字符(如\u200a),导致编码失败。
最优解决方法:直接保存原始二进制数据
EML文件本质是符合RFC822标准的原始邮件二进制数据,直接写入原始字节完全跳过编码解码步骤,既高效又彻底避免所有编码问题。
修改后的代码:
def download_emails(imap: imaplib.IMAP4_SSL, mail_count: int, output_directory: str) -> None: output_path = Path(output_directory) output_path.mkdir(parents=True, exist_ok=True) print(f"Starting email download to {output_directory}...") for i in range(mail_count, 0, -1): try: _, msg = imap.fetch(str(i), "(RFC822)") raw_email = msg[0][1] # 以二进制模式写入原始邮件数据,无编码解码操作 with open(output_path / f"{i}.eml", "wb") as f: f.write(raw_email) print(f"Downloaded email {i} of {mail_count}") except Exception as e: print(f"Error downloading email {i}: {e}") print("Email download complete.")
备选方案:处理字符串时兼容编码
如果确实需要解析邮件内容后再保存,可通过以下方式兼容编码:
- 解码时自动检测邮件编码,失败则用
replace忽略无效字符 - 写入文件时强制指定UTF-8编码
示例代码:
import email from email.header import decode_header def download_emails(imap: imaplib.IMAP4_SSL, mail_count: int, output_directory: str) -> None: output_path = Path(output_directory) output_path.mkdir(parents=True, exist_ok=True) print(f"Starting email download to {output_directory}...") for i in range(mail_count, 0, -1): try: _, msg = imap.fetch(str(i), "(RFC822)") raw_email = msg[0][1] # 尝试自动检测邮件编码,兜底用UTF-8替换错误字符 try: msg_obj = email.message_from_bytes(raw_email) charset = msg_obj.get_content_charset() or 'utf-8' raw_email_string = raw_email.decode(charset, errors='replace') except: raw_email_string = raw_email.decode('utf-8', errors='replace') # 写入时指定UTF-8编码,避免系统默认编码限制 with open(output_path / f"{i}.eml", "w", encoding='utf-8') as f: f.write(raw_email_string) print(f"Downloaded email {i} of {mail_count}") except Exception as e: print(f"Error downloading email {i}: {e}") print("Email download complete.")
优先推荐二进制写入方案,保存原始数据不会丢失任何邮件信息,是最可靠的处理方式。
内容的提问来源于stack exchange,提问作者Bruno Fischer
相关产品推荐
相关产品推荐

