概述
在日常工作生活中,都是利用个人或公司的邮箱客户端进行收发邮件,那么如何打造一款属于自己的邮箱客户端呢?本文以一个简单的小例子,简述如何通过Pyhton的imaplib和email两大模块,实现邮件的接收并展示,仅供学习分享使用,如有不足之处,还请指正。
什么是IMAP?
IMAP,即Internet Message Access Protocol(互联网邮件访问协议),您可以通过这种协议从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。
IMAP和POP有什么区别?
POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上的,比如:您通过电子邮件客户端收取了QQ邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,QQ邮箱服务器上的这些邮件是没有同时被移动的 。但是IMAP就不同了,电子邮件客户端的操作都会反馈到服务器上,您对邮件进行的操作(如:移动邮件、标记已读等),服务器上的邮件也会做相应的动作。也就是说,IMAP是“双向”的。
同时,IMAP可以只下载邮件的主题,只有当您真正需要的时候,才会下载邮件的所有内容。
如何设置IMAP服务的SSL加密方式?
使用SSL的通用配置如下:
接收邮件服务器:imap.qq.com,使用SSL,端口号993
发送邮件服务器:smtp.qq.com,使用SSL,端口号465或587
账户名:您的QQ邮箱账户名(如果您是VIP帐号或Foxmail帐号,账户名需要填写完整的邮件地址)
密码:您的QQ邮箱密码
电子邮件地址:您的QQ邮箱的完整邮件地址
涉及知识点
在本示例中,涉及知识点如下所示:
-
imaplib模块:此模块实现通过IMAP【Internet Message Access Protocol,信息交互访问协议】协议进行邮箱的登录,接收和发送等功能。
- IMAP4_SSL(host='',port=IMAP4_SSL_PORT),通过此方法可以定义一个IMAP对象,需要对应的服务器和端口号。
- login(self,user,password),通过此方法实现对应邮箱的登录,传入指定的账号,密码即可。
- select(self,mailbox='INBOX',readonly=False) 选择收件箱
- search(self,charset,*criteria) 查找获取邮箱数据
- fetch(self,message_set,message_parts) 通过邮件编号,查找具体的邮件内容
-
email模块:此模块主要用于邮件的解析功能
- message_from_string(s,*args,**kws) , 获取解析数据消息体
- email.header.decode_header(msg.get('Subject'))[0][1] 解析编码方式
- email.header.decode_header(msg.get('Date')) 解析邮件接收时间
- email.header.decode_header(msg.get('From'))[0][0] 解析发件人
- email.header.decode_header(msg.get('Subject'))[0][0].decode(msgCharset) 解析邮件标题
- email.utils.parseaddr(msg.get('Content-Transfer-Encoding'))[1] 解析邮件传输编码
示例效果图
示例分为两部分,左边是邮件列表,右边是邮件内容,如下所示:
核心代码
邮件帮助类,主要包括邮件的接收,具体邮件内容的解析等功能,如下所示:
1 import imaplib 2 email 3 datetime 4 5 6 class EmailUtil: 7 """ 8 Email帮助类 9 10 host = 'imap.qq.com' # 主机IP或者域名 11 port = 993 端口 12 username = ******** 用户名 13 password = ************** 密码或授权码 14 imap = None 邮箱连接对象 15 16 mail_box = '**************' # 邮箱名 17 18 def __init__(self,host,port): 19 """初始化方法 20 self.host = host 21 self.port = port 22 初始化一个邮箱链接对象 23 self.imap = imaplib.IMAP4_SSL(host=self.host,port=int(self.port)) 24 25 def login(self,username,password): 26 登录 27 self.username = username 28 self.password = password 29 self.imap.login(user=self.username,password=self.password) 30 31 get_mail(self): 32 获取邮件 33 self.mail_box = mail_box 34 email_infos = [] 35 if self.imap is not None: 36 self.imap.select(readonly=False) 37 typ,data = self.imap.search(None,ALL') 返回一个元组,data为此邮箱的所有邮件数据 38 数据格式 data = [b'1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18'] 39 if typ == OK': 40 for num in data[0].split(): 41 if int(num) > 10 42 超过20,退出循环,不输出 43 break 44 typ1,data1 = self.imap.fetch(num,1)">(RFC822) 通过邮箱编号和选择获取数据 45 if typ1 == 46 print(**********************************begin******************************************) 47 msg = email.message_from_string(data1[0][1].decode("utf-8")) 用email库获取解析数据(消息体) 48 获取邮件标题并进行进行解码,通过返回的元组的第一个元素我们得知消息的编码 49 msgCharset = email.header.decode_header(msg.get(Subject'))[0][1] 50 print('msg = ',msg) 51 print('msgCharset= ',msgCharset) # gb2312 52 recv_date = self.get_email_date(email.header.decode_header(msg.get(Date))) 53 mail_from = email.header.decode_header(msg.get(From))[0][0] 54 if type(mail_from) == bytes: 55 mail_from = mail_from.decode(msgCharset) 56 57 mail_to = email.header.decode_header(msg.get(To 58 subject = email.header.decode_header(msg.get('))[0][0].decode(msgCharset) 获取标题并通过标题进行解码 59 60 Message %s\n%s\n" % (num,subject)) 打印输出标题 61 mail_from:' + mail_from + mail_to:' + mail_to + recv_date:' + str(recv_date)) 62 # 邮件内容 63 for part in msg.walk(): 64 if not part.is_multipart(): 65 name = part.get_param("name") 66 if not name: # 如果邮件内容不是附件可以打印输出 67 print(part.get_payload(decode=True).decode(msgCharset)) 68 print('***********************************end*****************************************') 69 email_info = { 70 num": num, 71 subject: subject,1)"> 72 recv_date: recv_date,1)"> 73 mail_to: mail_to,1)"> 74 mail_from: mail_from 75 } 76 email_infos.append(email_info) 77 else 78 请先初始化并登录 79 return email_infos 80 81 get_email_content(self,num): 82 content = None 83 typ1,1)"> 84 85 86 msg = email.message_from_string(data1[0][1].decode( 87 print(msg) 88 89 msgCharset = email.header.decode_header(msg.get( 90 transfer_encoding = email.header.decode_header(msg.get('Content-Transfer-Encoding')) 91 transfer_encoding = email.utils.parseaddr(msg.get(Content-Transfer-Encoding'))[1 92 transfer_encoding:,transfer_encoding) 93 charset: 94 邮件内容 95 for part msg.walk(): 96 if part.is_multipart(): 97 name = part.get_param(name 98 not name: 如果邮件内容不是附件可以打印输出 99 if transfer_encoding == 8bit100 content = part.get_payload(decode=101 102 content = part.get_payload(decode=True).decode(msgCharset) 103 104 (content) 105 ***********************************end*****************************************106 content 107 108 get_email_date(self,date): 109 获取时间110 utcstr = date[0][0].replace(+00:00',1)">''111 utcdatetime =112 localtimestamp =113 try114 utcdatetime = datetime.datetime.strptime(utcstr,1)">%a,%d %b %Y %H:%M:%S +0000 (GMT)115 localdatetime = utcdatetime + datetime.timedelta(hours=+8116 localtimestamp = localdatetime.timestamp() 117 except118 119 utcdatetime = datetime.datetime.strptime(utcstr,%d %b %Y %H:%M:%S +0800 (CST)120 localtimestamp = utcdatetime.timestamp() 121 122 utcdatetime = datetime.datetime.strptime(utcstr,%d %b %Y %H:%M:%S +0800123 localtimestamp =124 localtimestamp 125 126 127 if __name__ == __main__128 host = 129 port = 130 username = 131 password = 密码 132 mail_box = 邮箱名 133 eamil_util = EmailUtil(host=host,1)">port) 134 eamil_util.login(username=username,1)">password) 135 eamil_util.get_mail() 136 done')
邮件展示类,主要用于邮件内容在前台页面的展示,如下所示:
1 from tkinter import * 2 from tkinterie.tkinterIE WebView 3 from test_email EmailUtil 4 time 5 os 6 7 Application(Frame): 8 email_util = 9 total_line= 0 10 11 __init__(self,master=None): 12 '''''' 13 super().__init__(master) 调用父类的初始化方法 14 host = 15 port = 16 username = *********17 password = 18 self.email_util = EmailUtil(host=host,1)">19 self.email_util.login(username=username,1)">20 self.master = master 21 self.pack(side=TOP,fill=BOTH,expand=1) # 此处填充父窗体 22 self.create_widget() 23 24 create_widget(self): 25 self.img_logo = PhotoImage(file=logo.png26 self.btn_logo = Button(image=self.img_logo,bg=#222E3C27 self.btn_logo.grid(row=0,column=0,sticky=N + E + W+S) 28 收件箱初始化 29 records = self.email_util.get_mail() 30 for i range(len(records)): 31 时间特殊处理 32 recv_date = time.strftime(%Y-%m-%d",time.localtime(records[i][])) 33 subject = {0} {1}".format(recv_date,records[i][]) 34 (subject) 35 num = records[i][36 btn_subject = Button(self.master,text=subject,height=2,width=30,bg=(#F0FFFF" if i%2==0 else #E6E6FA"),anchor=wlambda num=num: self.get_email_content(num) ) 37 btn_subject.grid(row=(i + 1),padx=2,pady=138 明细 39 self.total_line=i 40 self.web_view = WebView(self.master,width=530,height=56041 self.web_view.grid(row=0,column=1,rowspan=(i+2),pady=5,sticky=N + E + W) 42 43 44 获取邮件明细45 content = self.email_util.get_email_content(num) 46 47 if content.find(GBK')>0 or content.find(gbkcnblogs')>0: 48 1-111149 content = content.encode().decode('gbk') 50 print(content) 51 self.save_data(content) 52 abs_path = os.path.abspath(content.html53 self.web_view= WebView(self.master,height=560,url=file://"+abs_path) 54 self.web_view.grid(row=0,rowspan=(self.total_line + 2),padx=5,1)">55 56 57 save_data(self,content): 58 保存数据59 with open() as f: 60 f.write(content) 61 62 63 64 root = Tk() 65 root.title(个人邮箱66 root.geometry(760x580+200+20067 root.setvar(bgred68 app = Application(master=root) 69 root.mainloop()
邮箱设置
如果要使用IMAP协议访问邮箱服务进行收发邮件,则必须进行邮箱设置,路径:登录邮箱-->设置-->账户-->POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,如下所示:
如果通过邮箱账户密码登录时,报如下错误,则表示需要通过授权码进行登录,如下所示:
温馨提示:在第三方登录QQ邮箱,可能存在邮件泄露风险,甚至危害Apple ID安全,建议使用QQ邮箱手机版登录。
备注
逢雪宿芙蓉山主人
【作者】刘长卿【朝代】唐
日暮苍山远,天寒白屋贫。柴门闻犬吠,风雪夜归人。
原文地址:https://www.cnblogs.com/hsiang
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。