赞
踩
在日常工作生活中,都是利用个人或公司的邮箱客户端进行收发邮件,那么如何打造一款属于自己的邮箱客户端呢?本文以一个简单的小例子,简述如何通过Pyhton的imaplib和email两大模块,实现邮件的接收并展示,仅供学习分享使用,如有不足之处,还请指正。
IMAP,即Internet Message Access Protocol(互联网邮件访问协议),您可以通过这种协议从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。
POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上的,比如:您通过电子邮件客户端收取了QQ邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,QQ邮箱服务器上的这些邮件是没有同时被移动的 。但是IMAP就不同了,电子邮件客户端的操作都会反馈到服务器上,您对邮件进行的操作(如:移动邮件、标记已读等),服务器上的邮件也会做相应的动作。也就是说,IMAP是“双向”的。
同时,IMAP可以只下载邮件的主题,只有当您真正需要的时候,才会下载邮件的所有内容。
使用SSL的通用配置如下:
在本示例中,涉及知识点如下所示:
示例分为两部分,左边是邮件列表,右边是邮件内容,如下所示:
邮件帮助类,主要包括邮件的接收,具体邮件内容的解析等功能,如下所示:
- import imaplib
- import email
- import datetime
-
-
- class EmailUtil:
- """
- Email帮助类
- """
- host = 'imap.qq.com' # 主机IP或者域名
- port = '993' # 端口
- username = '********' # 用户名
- password = '**************' # 密码或授权码
- imap = None # 邮箱连接对象
-
- # mail_box = '**************' # 邮箱名
-
- def __init__(self, host, port):
- """初始化方法"""
- self.host = host
- self.port = port
- # 初始化一个邮箱链接对象
- self.imap = imaplib.IMAP4_SSL(host=self.host, port=int(self.port))
-
- def login(self, username, password):
- """登录"""
- self.username = username
- self.password = password
- self.imap.login(user=self.username, password=self.password)
-
- def get_mail(self):
- """获取邮件"""
- # self.mail_box = mail_box
- email_infos = []
- if self.imap is not None:
- self.imap.select(readonly=False)
- typ, data = self.imap.search(None, 'ALL') # 返回一个元组,data为此邮箱的所有邮件数据
- # 数据格式 data = [b'1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18']
- if typ == 'OK':
- for num in data[0].split():
- if int(num) > 10:
- # 超过20,退出循环,不输出
- break
- typ1, data1 = self.imap.fetch(num, '(RFC822)') # 通过邮箱编号和选择获取数据
- if typ1 == 'OK':
- print('**********************************begin******************************************')
- msg = email.message_from_string(data1[0][1].decode("utf-8")) # 用email库获取解析数据(消息体)
- # 获取邮件标题并进行进行解码,通过返回的元组的第一个元素我们得知消息的编码
- msgCharset = email.header.decode_header(msg.get('Subject'))[0][1]
- # print('msg = ',msg)
- # print('msgCharset= ',msgCharset) # gb2312
- recv_date = self.get_email_date(email.header.decode_header(msg.get('Date')))
- mail_from = email.header.decode_header(msg.get('From'))[0][0]
- if type(mail_from) == bytes:
- mail_from = mail_from.decode(msgCharset)
-
- mail_to = email.header.decode_header(msg.get('To'))[0][0]
- subject = email.header.decode_header(msg.get('Subject'))[0][0].decode(msgCharset) # 获取标题并通过标题进行解码
-
- print("Message %s\n%s\n" % (num, subject)) # 打印输出标题
- print('mail_from:' + mail_from + ' mail_to:' + mail_to + ' recv_date:' + str(recv_date))
- # # 邮件内容
- # for part in msg.walk():
- # if not part.is_multipart():
- # name = part.get_param("name")
- # if not name: # 如果邮件内容不是附件可以打印输出
- # print(part.get_payload(decode=True).decode(msgCharset))
- # print('***********************************end*****************************************')
- email_info = {
- "num": num,
- "subject": subject,
- "recv_date": recv_date,
- "mail_to": mail_to,
- "mail_from": mail_from
- }
- email_infos.append(email_info)
- else:
- print('请先初始化并登录')
- return email_infos
-
- def get_email_content(self, num):
- content = None
- typ1, data1 = self.imap.fetch(num, '(RFC822)') # 通过邮箱编号和选择获取数据
- if typ1 == 'OK':
- print('**********************************begin******************************************')
- msg = email.message_from_string(data1[0][1].decode("utf-8")) # 用email库获取解析数据(消息体)
- print(msg)
- # 获取邮件标题并进行进行解码,通过返回的元组的第一个元素我们得知消息的编码
- msgCharset = email.header.decode_header(msg.get('Subject'))[0][1]
- # transfer_encoding = email.header.decode_header(msg.get('Content-Transfer-Encoding'))
- transfer_encoding = email.utils.parseaddr(msg.get('Content-Transfer-Encoding'))[1]
- print("transfer_encoding:",transfer_encoding)
- print("charset:",msgCharset)
- # 邮件内容
- for part in msg.walk():
- if not part.is_multipart():
- name = part.get_param("name")
- if not name: # 如果邮件内容不是附件可以打印输出
- if transfer_encoding == '8bit':
- content = part.get_payload(decode=False)
- else:
- content = part.get_payload(decode=True).decode(msgCharset)
-
- print(content)
- print('***********************************end*****************************************')
- return content
-
- def get_email_date(self, date):
- """获取时间"""
- utcstr = date[0][0].replace('+00:00', '')
- utcdatetime = None
- localtimestamp = None
- try:
- utcdatetime = datetime.datetime.strptime(utcstr, '%a, %d %b %Y %H:%M:%S +0000 (GMT)')
- localdatetime = utcdatetime + datetime.timedelta(hours=+8)
- localtimestamp = localdatetime.timestamp()
- except:
- try:
- utcdatetime = datetime.datetime.strptime(utcstr, '%a, %d %b %Y %H:%M:%S +0800 (CST)')
- localtimestamp = utcdatetime.timestamp()
- except:
- utcdatetime = datetime.datetime.strptime(utcstr, '%a, %d %b %Y %H:%M:%S +0800')
- localtimestamp = utcdatetime.timestamp()
- return localtimestamp
-
-
- if __name__ == '__main__':
- host = 'imap.qq.com' # 主机IP或者域名
- port = '993' # 端口
- username = '********' # 用户名
- password = '**************' # 密码
- mail_box = '**************' # 邮箱名
- eamil_util = EmailUtil(host=host, port=port)
- eamil_util.login(username=username, password=password)
- eamil_util.get_mail()
- print('done')
邮件展示类,主要用于邮件内容在前台页面的展示,如下所示:
- from tkinter import *
- from tkinterie.tkinterIE import WebView
- from test_email import EmailUtil
- import time
- import os
-
- class Application(Frame):
- email_util = None
- total_line= 0
-
- def __init__(self, master=None):
- '''初始化方法'''
- super().__init__(master) # 调用父类的初始化方法
- host = 'imap.qq.com' # 主机IP或者域名
- port = '993' # 端口
- username = '*********' # 用户名
- password = '**************' # 密码或授权码
- self.email_util = EmailUtil(host=host, port=port)
- self.email_util.login(username=username, password=password)
- self.master = master
- # self.pack(side=TOP, fill=BOTH, expand=1) # 此处填充父窗体
- self.create_widget()
-
- def create_widget(self):
- self.img_logo = PhotoImage(file="logo.png")
- self.btn_logo = Button(image=self.img_logo , bg='#222E3C')
- self.btn_logo.grid(row=0, column=0, sticky=N + E + W+S)
- # 收件箱初始化
- records = self.email_util.get_mail()
- for i in range(len(records)):
- # 时间特殊处理
- recv_date = time.strftime("%Y-%m-%d", time.localtime(records[i]["recv_date"]))
- subject = "{0} {1}".format(recv_date, records[i]["subject"])
- print(subject)
- num = records[i]["num"]
- btn_subject = Button(self.master, text=subject,height=2, width=30, bg=("#F0FFFF" if i%2==0 else "#E6E6FA"), anchor='w',command=lambda num=num: self.get_email_content(num) )
- btn_subject.grid(row=(i + 1), column=0, padx=2, pady=1)
- # 明细
- self.total_line=i
- self.web_view = WebView(self.master, width=530, height=560)
- self.web_view.grid(row=0, column=1, rowspan=(i+2), padx=2, pady=5, sticky=N + E + W)
-
- def get_email_content(self,num):
- """获取邮件明细"""
- content = self.email_util.get_email_content(num)
- print(content)
- if content.find('GBK')>0 or content.find('gbk')>0 or content.find('cnblogs')>0:
- print('1-1111')
- # content = content.encode().decode('gbk')
- # print(content)
- self.save_data(content)
- abs_path = os.path.abspath("content.html")
- self.web_view= WebView(self.master, width=530, height=560,url="file://"+abs_path)
- self.web_view.grid(row=0, column=1, rowspan=(self.total_line + 2), padx=5, pady=5, sticky=N + E + W)
-
-
- def save_data(self,content):
- """保存数据"""
- with open('content.html', 'w', encoding='utf-8') as f:
- f.write(content)
-
-
- if __name__ == '__main__':
- root = Tk()
- root.title('个人邮箱')
- root.geometry('760x580+200+200')
- root.setvar("bg", "red")
- app = Application(master=root)
- root.mainloop()
如果要使用IMAP协议访问邮箱服务进行收发邮件,则必须进行邮箱设置,路径:登录邮箱-->设置-->账户-->POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,如下所示:
如果通过邮箱账户密码登录时,报如下错误,则表示需要通过授权码进行登录,如下所示:
温馨提示:在第三方登录QQ邮箱,可能存在邮件泄露风险,甚至危害Apple ID安全,建议使用QQ邮箱手机版登录。
逢雪宿芙蓉山主人
【作者】刘长卿【朝代】唐
日暮苍山远,天寒白屋贫。柴门闻犬吠,风雪夜归人。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。