如何获取邮件正文文本?Python IMAP邮件读取问题求助
问题描述
使用Python的imaplib和email库读取邮件时,无法获取邮件正文文本,得到的是email.message.Message对象列表。请问是否需要对邮件文本进行解码?如何才能实际获取到邮件正文文本?
代码示例
读取邮件的函数
import sys import imaplib import getpass import email import email.header from email.header import decode_header import base64 def read(username, password, sender_of_interest): # Login to INBOX imap = imaplib.IMAP4_SSL("imap.mail.com", 993) imap.login(username, password) imap.select('INBOX') # Use search(), not status() # Print all unread messages from a certain sender of interest if sender_of_interest: status, response = imap.uid('search', None, 'UNSEEN', 'FROM {0}'.format(sender_of_interest)) else: status, response = imap.uid('search', None, 'UNSEEN') if status == 'OK': unread_msg_nums = response[0].split() else: unread_msg_nums = [] data_list = [] for e_id in unread_msg_nums: data_dict = {} e_id = e_id.decode('utf-8') _, response = imap.uid('fetch', e_id, '(RFC822)') html = response[0][1].decode('utf-8') email_message = email.message_from_string(html) data_dict['mail_to'] = email_message['To'] data_dict['mail_subject'] = email_message['Subject'] data_dict['mail_from'] = email.utils.parseaddr(email_message['From']) #data_dict['body'] = email_message.get_payload()[0].get_payload() data_dict['body'] = email_message.get_payload() data_list.append(data_dict) print(data_list) # Mark them as seen #for e_id in unread_msg_nums: #imap.store(e_id, '+FLAGS', '\Seen') imap.logout() return data_dict
调用代码
print('Getting the email text bodiies ... ') emailData = read(usermail, pw, sender_of_interest) print('Got the data!') for key in emailData.keys(): print(key, emailData[key])
运行输出
mail_to me@mail.com
mail_subject Get json file
mail_from ('Pedro Rodriguez', 'pedro@gmail.com')
body [<email.message.Message object at 0x7f7d9f928df0>, <email.message.Message object at 0x7f7d9f928f70>]
解决方案
你遇到的情况是因为邮件是多部分(multipart)格式,这类邮件通常包含纯文本、HTML等多个版本的正文,此时email_message.get_payload()会返回各个部分对应的email.message.Message对象列表,而非直接返回文本内容。需要针对邮件结构处理,同时解决内容编码问题。
步骤1:添加正文提取逻辑
新增一个函数处理邮件正文的提取,核心逻辑:
- 判断邮件是否为多部分格式,是则遍历所有子部分;否则直接提取内容
- 针对
text/plain或text/html类型的内容,解码后拼接成完整正文
修改后的完整代码
import sys import imaplib import getpass import email import email.header from email.header import decode_header import base64 def extract_email_body(email_message): body = "" # 判断邮件是否为多部分格式 if email_message.is_multipart(): # 遍历所有子部分 for part in email_message.get_payload(): # 只处理纯文本和HTML类型内容 if part.get_content_type() in ["text/plain", "text/html"]: # 获取内容并处理编码 charset = part.get_content_charset() if charset: body += part.get_payload(decode=True).decode(charset) else: # 无法获取编码时用UTF-8兜底,替换错误字符 body += part.get_payload(decode=True).decode('utf-8', errors='replace') else: # 非多部分邮件直接提取内容 charset = email_message.get_content_charset() if charset: body = email_message.get_payload(decode=True).decode(charset) else: body = email_message.get_payload(decode=True).decode('utf-8', errors='replace') return body def read(username, password, sender_of_interest): # Login to INBOX imap = imaplib.IMAP4_SSL("imap.mail.com", 993) imap.login(username, password) imap.select('INBOX') # 搜索未读邮件 if sender_of_interest: status, response = imap.uid('search', None, 'UNSEEN', 'FROM {0}'.format(sender_of_interest)) else: status, response = imap.uid('search', None, 'UNSEEN') if status == 'OK': unread_msg_nums = response[0].split() else: unread_msg_nums = [] data_list = [] for e_id in unread_msg_nums: data_dict = {} e_id = e_id.decode('utf-8') _, response = imap.uid('fetch', e_id, '(RFC822)') # 直接用原始字节解析邮件,避免编码转换错误 email_message = email.message_from_bytes(response[0][1]) # 解码邮件主题(解决乱码问题) subject, encoding = decode_header(email_message['Subject'])[0] if isinstance(subject, bytes): subject = subject.decode(encoding if encoding else 'utf-8') data_dict['mail_to'] = email_message['To'] data_dict['mail_subject'] = subject data_dict['mail_from'] = email.utils.parseaddr(email_message['From']) # 提取正文 data_dict['body'] = extract_email_body(email_message) data_list.append(data_dict) print(data_list) imap.logout() # 修正返回值:返回所有未读邮件的列表,而非最后一封 return data_list
关键优化点
- 多部分邮件处理:通过
is_multipart()识别邮件结构,遍历子部分提取有效文本内容 - 编码自动解码:使用
get_payload(decode=True)自动解码Base64/Quoted-Printable编码的内容,再根据邮件指定字符集转成字符串 - 主题乱码修复:用
decode_header处理带编码的邮件主题,避免乱码 - 解析方式优化:用
email.message_from_bytes直接解析原始字节数据,比先转字符串更稳妥
修正后的调用代码
print('获取邮件正文... ') emailDataList = read(usermail, pw, sender_of_interest) print('获取完成!') for emailData in emailDataList: print('--- 邮件信息 ---') for key, value in emailData.items(): print(f'{key}: {value}')
内容的提问来源于stack exchange,提问作者Pedroski
相关产品推荐
相关产品推荐

