You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取邮件正文文本?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

关键优化点

  1. 多部分邮件处理:通过is_multipart()识别邮件结构,遍历子部分提取有效文本内容
  2. 编码自动解码:使用get_payload(decode=True)自动解码Base64/Quoted-Printable编码的内容,再根据邮件指定字符集转成字符串
  3. 主题乱码修复:用decode_header处理带编码的邮件主题,避免乱码
  4. 解析方式优化:用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:18:13