使用python自带的email模块解析邮件

(本文最先发表于Zhu's Blog,未经书面授权许可,任何个人和组织不得以任何形式转载、引用本人的任何文章。本人保留追究侵权者法律责任的权利。)

      这里阿猪假设你已经通过pop、imap等方式获取到了一封邮件,或者有一个现成的eml文件。下边的代码着重演示解析邮件内容过程中的基本实现方法。

import imaplib
from email.parser import Parser
from email.header import decode_header
import re
import datetime

imap_user = '用户名email地址'
imap_object = imaplib.IMAP4_SSL(port="993",host="imap.xxx.com") #如果使用非安全链接,请尝试使用imaplib的IMAP4方法
imap_object.login(imap_user, '密码或授权码')
imap_object.select('INBOX')  #选择'收件箱'
typ, msg_ids = imap_object.search(None, 'ALL')

ids = msg_ids[0]
ret = ids.decode('utf-8')
message_id_list = ret.split()
int_mail_num =  len(message_id_list)
print('收件箱中共有%s封邮件'%int_mail_num)

msg = msg_ids[0]
msg_list = msg.split()
#print('msg_list=',msg_list)
ids = msg_list[0] #选择第1封邮件
results, data = imap_object.fetch(ids, "(RFC822)")
imap_object.close() #关闭与imap服务器的连接
str_source = data[0][1].decode('UTF-8')
###############以上内容不是本文的重点,只是为了测试时保持连贯#############


msg_email = Parser().parsestr(str_source) #从string中读取邮件源文件,返回email.message格式的数据
#如果你是从eml文件中加载邮件源文件,请尝试通过email模块的message_from_file方法(未测试)
#import email
#fp = open("xxx.eml","r")
#msg_email = email.message_from_file(fp)

str_from = msg_email["from"] #提取发件人信息
#tuple_from = email.utils.parseaddr(str_from) #也可用email.utils中的parseaddr方法提取发件人名称和地址(收件人也一样),此处未使用该方法,是因为测试时发现解析email地址为空的email时会发生把名称解析为地址的错误
#str_from_name = tuple_from[0]
#str_from_address = tuple_from[1]
str_from_name = re.search(r'(?<=")[\s\S]*?(?=")',str_from).group() #通过正则表达式提取发件人名称(解码前)
str_from_address = re.search(r'(?<=<)[\s\S]*?(?=>)',str_from).group() #通过正则表达式提取发件人email地址
value, charset = decode_header(str_from_name)[0] #提取发件人名称的数据和编码信息
if charset: #如果指定了编码
    str_from_name = value.decode(charset) #则使用email模块的decode方法解码
print(">>From:%s<%s>"%(str_from_name,str_from_address))

str_to = msg_email["to"] #提取收件人信息
str_to_name = re.search(r'(?<=")[\s\S]*?(?=")',str_to).group() #通过正则表达式提取收件人名称(解码前)
str_to_address = re.search(r'(?<=<)[\s\S]*?(?=>)',str_to).group() #通过正则表达式提取收件人email地址()
value, charset = decode_header(str_to_name)[0] #提取收件人名称的数据和编码信息
if charset: #如果指定了编码
    str_to_name = value.decode(charset) #则使用email模块的decode方法解码
print(">>To:%s<%s>"%(str_to_name,str_to_address))

str_date = msg_email["date"] #提取日期
str_date = str_date.replace('GMT','+0000') #测试时遇到有GMT+0:00时区的邮件服务器不使用通用的时区格式
dtime_date = datetime.datetime.strptime(str_date, '%a, %d %b %Y %H:%M:%S %z') #将string格式的日期数据转换为含有时区信息的datetime
print('>>时间:%s'%dtime_date)

str_subject = msg_email["subject"] #提取邮件主题
value, charset = decode_header(str_subject)[0] #提取邮件主题的数据和编码信息
if charset: #如果指定了编码
    str_subject = value.decode(charset) #则使用email模块的decode方法解码
print('>>邮件主题:%s'%str_subject)

def decode_mime(msg): #此处封装的目的是在循环处理MIME数据块时重复利用代码(找不到这段代码的出处了,日后找到再补上出处。)
    if msg.is_multipart(): #如果 MIME数据的格式是multi-part
        parts = msg.get_payload()
        for part in parts: #则遍历挨个解析
            decode_mime(part) #拆分出的单个数据块再次传入自定义函数decode_mime(相当于创建了一个新的实例,与当前的循环不冲突)
    else: #处理每一个MIME数据块
        str_content_type = msg.get_content_type() #当前数据块的Content-Type
        #print('str_content_type=%s'%str_content_type)
        str_charset = msg.get_content_charset(failobj=None) #当前数据块的编码信息
        #print('str_charset=',str_charset)
        if str_content_type in ('text/plain', 'text/html'): #这里只处理纯文本、html两类数据,关于附件和其他类型数据的处理方法,请继续询问度娘
            bytes_content = msg.get_payload(decode=True) #读取当前数据块中的正文内容,返回bytes
            str_content = bytes_content.decode(str_charset) #解码
            print('>>邮件正文(%s):%s'%(str_content_type,str_content))
#目前的email普遍采用同样内容的一封邮件同时包含纯文本、html两种类型的MIME,所以解析出的邮件正文看起来像是重复的。可根据需要自行进一步处理。
# 原文发表自 Zhu's Blog https://azhu.site/posts/phrasing-email-with-email-model/
#本代码只演示解析邮件内容过程中的基本实现方法,未进行过多的容错和封装处理,可根据需要自行进一步处理。
decode_mime(msg_email)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值