如何让email.message_from_bytes兼容Unicode/Emoji输入避免报错
问题
使用email.message_from_bytes()处理包含Unicode/Emoji的邮件头时,会触发意外的TypeError,同时邮件头中的Emoji会显示为乱码。需要通过编码/解码处理,让gyb.py能正常清理恢复含Unicode/Emoji的.eml备份文件,且字符不损坏。
最小复现代码
import email f = open('./sample.eml', 'rb') bytes = f.read() message = email.message_from_bytes(bytes) # 无Unicode/Emoji:正常工作 print(message['to']) print(len(message['to'])) # 含Unicode/Emoji:出现意外TypeError print(message['from']) print(len(message['from']))
sample.eml内容
To: recipient <to@example.com> From:🔥sender🔥 <from@example.com>
运行输出
$ python check-message.py recipient <to@example.com> 26 ����sender���� <from@example.com> Traceback (most recent call last): File "V:\gyb\jkm\check-message.py", line 10, in <module> print(len(message['from'])) ^^^^^^^^^^^^^^^^^^^^ TypeError: object of type 'Header' has no len()
解决方法
1. 用现代化解析策略(最简便)
Python 3.3+的email模块提供了默认策略,能自动处理Unicode邮件头,直接返回字符串而非Header对象,彻底解决问题:
import email f = open('./sample.eml', 'rb') bytes = f.read() # 指定默认策略解析 message = email.message_from_bytes(bytes, policy=email.policy.default) print(message['to']) print(len(message['to'])) print(message['from']) # 正确显示🔥sender🔥 <from@example.com> print(len(message['from'])) # 正常获取长度
2. 解析后处理Header对象
如果不能修改解析策略,可直接将返回的Header对象转为字符串,解决乱码和len()调用失败问题:
import email f = open('./sample.eml', 'rb') bytes = f.read() message = email.message_from_bytes(bytes) # 正常处理无Unicode的头 print(message['to']) print(len(message['to'])) # 处理含Emoji的头 from_header = message['from'] from_str = str(from_header) print(from_str) # 正确显示🔥sender🔥 <from@example.com> print(len(from_str)) # 正常获取长度
3. 预处理.eml文件(修复非标准邮件头)
原始.eml的邮件头未按MIME规范编码(直接用了未编码的Emoji),可提前将其转为标准Encoded-Word格式:
import email from email.header import Header # 读取并解码.eml内容 with open('./sample.eml', 'rb') as f: eml_content = f.read().decode('utf-8') # 拆分邮件头和正文 header_part, body_part = eml_content.split('\n\n', 1) new_headers = [] for line in header_part.splitlines(): if line.startswith('From:'): # 拆分名称和邮箱部分 name_part = line.split('<')[0].replace('From:', '').strip() email_part = line.split('<')[1].strip() # 编码含Emoji的名称为标准格式 encoded_name = Header(name_part, 'utf-8').encode() new_from = f'From: {encoded_name} <{email_part}' new_headers.append(new_from) else: new_headers.append(line) # 重新组合并转为二进制 fixed_eml_content = '\n'.join(new_headers) + '\n\n' + body_part fixed_eml_bytes = fixed_eml_content.encode('utf-8') # 解析修复后的内容 message = email.message_from_bytes(fixed_eml_bytes) print(message['from']) print(len(str(message['from'])))
内容的提问来源于stack exchange,提问作者Leftium
相关产品推荐
相关产品推荐

