我的知识记录

Python解析邮件正文 HTML转纯文本 完整教程

用Python标准库email模块解析MIME邮件,同时提取纯文本正文和HTML正文,HTML自动去标签转纯文本,解决中文乱码和多版本正文问题,附完整代码。

场景痛点

邮件抓到了,但正文是一坨HTML标签混着base64编码,直接打印全是<div><br>,根本读不通。客户的报价条款、合同备注、订单信息都藏在正文里,需要自动抽取成干净文本存下来分析。用标准库把纯文本和HTML正文分别处理,HTML自动去标签,拿到可读的纯文字。

用到的库

imaplib、html.parser都是Python标准库,无需pip安装。

# 无需安装,Python3自带

完整代码

# -*- coding: utf-8 -*-
import re
from email.header import decode_header, make_header
from html.parser import HTMLParser


class _TextExtractor(HTMLParser):
"""把HTML里的标签剥掉,只留文字"""
def __init__(self):
super().__init__()
self._chunks = []

def handle_data(self, data):
self._chunks.append(data)

def text(self):
return "".join(self._chunks)


def html_to_text(html_str):
p = _TextExtractor()
p.feed(html_str)
txt = p.text()
# 压缩多余空白和空行
txt = re.sub(r"[ \t]+", " ", txt)
txt = re.sub(r"\n\s*\n+", "\n\n", txt)
return txt.strip()


def decode_str(s):
if not s:
return ""
return str(make_header(decode_header(s)))


def get_body(msg):
"""
返回 (纯文本正文, HTML正文)
一封邮件可能同时有text/plain和text/html两个版本
"""
plain, html = "", ""
for part in msg.walk():
if part.get_content_maintype() != "text":
continue
if part.get("Content-Disposition", "").startswith("attachment"):
continue  # 带附件标记的text不算正文
charset = part.get_content_charset() or "utf-8"
try:
raw = part.get_payload(decode=True)
text = raw.decode(charset, errors="ignore")
except LookupError:
text = raw.decode("utf-8", errors="ignore")

if part.get_content_type() == "text/plain":
plain = text
elif part.get_content_type() == "text/html":
html = text
return plain, html


def demo():
# 完整登录+读取示例
import imaplib
import email

IMAP_SERVER = "imap.qq.com"
ACCOUNT = "your_account@qq.com"
PASSWORD = "your_imap_auth_code"

mail = imaplib.IMAP4_SSL(IMAP_SERVER, 993)
mail.login(ACCOUNT, PASSWORD)
mail.select("INBOX")
_, msgs = mail.search(None, "ALL")
ids = msgs[0].split()[-5:]

for mid in reversed(ids):
_, data = mail.fetch(mid, "(BODY.PEEK[])")
msg = email.message_from_bytes(data[0][1])
print("=" * 60)
print("主题:", decode_str(msg.get("Subject")))
plain, html = get_body(msg)
if plain:
print("--- 纯文本正文 ---")
print(plain[:500])
if html:
print("--- HTML正文转纯文本 ---")
print(html_to_text(html)[:500])
mail.logout()


if __name__ == "__main__":
demo()

代码讲解

  • msg.walk()遍历MIME结构时,正文部分get_content_maintype()text,附件部分不是。用这个判断把正文挑出来。
  • 一封邮件常有两个text part:text/plain是纯文本版,text/html是网页版。把它们分别存下来,优先用纯文本版,没有再用HTML转。
  • Content-Disposition带attachment的text part其实是附件(比如有些邮件把.txt当附件发),要跳过,别当成正文。
  • HTMLParser是标准库,继承它重写handle_data就能把HTML里所有可见文本收集起来,不用装BeautifulSoup。
  • 正则[ \t]+\n\s*\n+把HTML转出来的文本里多余空格、空行压缩一下,可读性好很多。
  • 字符集兜底:先取邮件声明的charset,遇到gbk、gb2312等不认识的,回退utf-8并用errors="ignore"忽略坏字节,不会因为编码问题崩。

运行结果

终端打印最近5封邮件的主题、纯文本正文前500字;如果邮件只有HTML版,就打印去标签后的纯文本。中文正常,没有HTML标签残留。

注意事项

  • 只剥标签不处理JS/CSS:<script><style>里的内容会被当成文本抓出来。需要更干净的话,在HTMLParser里遇到这两个标签就标记忽略内容。
  • 邮件正文里的回复引用(>开头的历史回复)也会一起抽出来,做摘要时可以按>行过滤掉。
  • 中文编码最常见的坑是gbk邮件用utf-8解会乱码。一定要用get_content_charset(),别硬编码utf-8。
  • 想要更强的HTML清洗(保留链接、表格),可以装pip install beautifulsoup4,用BeautifulSoup(html, "html.parser").get_text(),效果一样但更省事。
  • 正文里的换行、空格在邮件客户端看着正常,解析出来可能挤成一团,要按业务需要自己分段。

Python解析邮件正文 HTML转纯文本 完整教程

标签:

更新时间:2026-09-14 21:07:26

上一篇:Python使用QQ邮箱SMTP发送邮件 详细教程

下一篇:Python把收到的Excel附件自动合并汇总