概述

在日常工作生活中,都是利用个人或公司的邮箱客户端进行收发邮件,那么如何打造一款属于自己的邮箱客户端呢?本文以一个简单的小例子,简述如何通过Pyhton的imaplib和email两大模块,实现邮件的接收并展示,仅供学习分享使用,如有不足之处,还请指正。

什么是IMAP?

IMAP,即Internet Message Access Protocol(互联网邮件访问协议),您可以通过这种协议从邮件服务器上获取邮件的信息、下载邮件等。IMAP与POP类似,都是一种邮件获取协议。

IMAP和POP有什么区别?

POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上的,比如:您通过电子邮件客户端收取了QQ邮箱中的3封邮件并移动到了其他文件夹,这些移动动作是不会反馈到服务器上的,也就是说,QQ邮箱服务器上的这些邮件是没有同时被移动的 。但是IMAP就不同了,电子邮件客户端的操作都会反馈到服务器上,您对邮件进行的操作(如:移动邮件、标记已读等),服务器上的邮件也会做相应的动作。也就是说,IMAP是“双向”的。

同时,IMAP可以只下载邮件的主题,只有当您真正需要的时候,才会下载邮件的所有内容。

如何设置IMAP服务的SSL加密方式?

使用SSL的通用配置如下:

  1. 接收邮件服务器:imap.qq.com,使用SSL,端口号993
  2. 发送邮件服务器:smtp.qq.com,使用SSL,端口号465或587
  3. 账户名:您的QQ邮箱账户名(如果您是VIP帐号或Foxmail帐号,账户名需要填写完整的邮件地址)
  4. 密码:您的QQ邮箱密码
  5. 电子邮件地址:您的QQ邮箱的完整邮件地址

涉及知识点

在本示例中,涉及知识点如下所示:

  • imaplib模块:此模块实现通过IMAP【Internet Message Access Protocol,信息交互访问协议】协议进行邮箱的登录,接收和发送等功能。
  1. IMAP4_SSL(host='', port=IMAP4_SSL_PORT),通过此方法可以定义一个IMAP对象,需要对应的服务器和端口号。
  2. login(self, user, password),通过此方法实现对应邮箱的登录,传入指定的账号,密码即可。
  3. select(self, mailbox='INBOX', readonly=False) 选择收件箱
  4. search(self, charset, *criteria) 查找获取邮箱数据
  5. fetch(self, message_set, message_parts) 通过邮件编号,查找具体的邮件内容
  • email模块:此模块主要用于邮件的解析功能
  1. message_from_string(s, *args, **kws) , 获取解析数据消息体
  2. email.header.decode_header(msg.get('Subject'))[0][1] 解析编码方式
  3. email.header.decode_header(msg.get('Date')) 解析邮件接收时间
  4. email.header.decode_header(msg.get('From'))[0][0] 解析发件人
  5. email.header.decode_header(msg.get('Subject'))[0][0].decode(msgCharset) 解析邮件标题
  6. email.utils.parseaddr(msg.get('Content-Transfer-Encoding'))[1] 解析邮件传输编码

示例效果图

示例分为两部分,左边是邮件列表,右边是邮件内容,如下所示:

核心代码

邮件帮助类,主要包括邮件的接收,具体邮件内容的解析等功能,如下所示:

import imaplib
import email
import datetimeclass EmailUtil:"""Email帮助类"""host = 'imap.qq.com'  # 主机IP或者域名port = '993'  # 端口username = '********'  # 用户名password = '**************'  # 密码或授权码imap = None  # 邮箱连接对象# mail_box = '**************'  # 邮箱名def __init__(self, host, port):"""初始化方法"""self.host = hostself.port = port# 初始化一个邮箱链接对象self.imap = imaplib.IMAP4_SSL(host=self.host, port=int(self.port))def login(self, username, password):"""登录"""self.username = usernameself.password = passwordself.imap.login(user=self.username, password=self.password)def get_mail(self):"""获取邮件"""# self.mail_box = mail_boxemail_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,退出循环,不输出breaktyp1, 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)  # gb2312recv_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_infosdef get_email_content(self, num):content = Nonetyp1, 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 contentdef get_email_date(self, date):"""获取时间"""utcstr = date[0][0].replace('+00:00', '')utcdatetime = Nonelocaltimestamp = Nonetry: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 localtimestampif __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 osclass Application(Frame):email_util = Nonetotal_line= 0def __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=iself.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邮箱手机版登录。

备注

逢雪宿芙蓉山主人

【作者】刘长卿【朝代】唐

日暮苍山远,天寒白屋贫。柴门闻犬吠,风雪夜归人。

Python通过IMAP实现邮箱客户端相关推荐

  1. 手机qq邮箱pop3服务器是什么意思,qq邮箱pop3是什么意思怎么弄(邮箱客户端设置中IMAP和POP3有什么区别)...

    然则在设置账户信息的时候不知道你有没有注重到IMAP和POP3两种设置类型,那么邮箱客户端设置中IMAP和POP3有什么区别? POP3和谈许可电子邮件客户端下载办事器上的邮件,然则在客户端的把持(如 ...

  2. python:imaplib --- IMAP4 协议客户端

    python:imaplib --- IMAP4 协议客户端 简介 IMAP4 对象 IMAP4 示例 简介 本模块定义了三个类: IMAP4 . IMAP4_SSL 和 IMAP4_stream . ...

  3. python:poplib --- POP3 协议客户端

    python:poplib --- POP3 协议客户端 简介 POP3 对象 POP3 示例 简介 本模块定义了一个 POP3 类,该类封装了到 POP3 服务器的连接过程,并实现了 RFC 193 ...

  4. Python实现IMAP协议接收并解析邮件内容

    Python实现IMAP协议接收并解析邮件内容 **前言:**昨天接到这个任务,然后搜索了很多资料和博客去看,这些资料链接我会放在本文后面 一.开通IMAP服务 我以网页邮箱(163邮箱为例) 1.登 ...

  5. evolution ubuntu邮箱_Ubuntu下使用Evolution电子邮箱客户端

    =摘要= 话说一直是使用web的邮箱客户端,今天想了想应该试试Evolution这个linux下面的邮箱客户端.搞了搞,能够正常收发邮件了呵呵,在能够接收邮件的同时,现在也不用每一次都得登录到web邮 ...

  6. python编写游戏测试机器人客户端(一)

    系列文章目录 python编写游戏测试机器人客户端(一) python编写游戏测试机器人客户端(二) python编写游戏测试机器人客户端(三) python编写游戏测试机器人客户端(四) pytho ...

  7. 网易163邮箱配置-iOS、OS X邮箱客户端

    最近在找工作,及时收取笔试和面试通知邮件是非常有必要的,想用一个客户端同时收取foxmail邮箱和163邮箱.有人会说,用一个邮箱不就行了,干嘛自己给自己找麻烦?那么问题来了,碰上个死对头公司,像36 ...

  8. 邮件服务器怎么填,如何配置邮箱客户端?

    在邮箱客户端登录邮箱时,经常会提示服务器地址错误.这是怎么回事呢?其实,每一款邮箱的收发邮件地址都是不同的,如果使用邮箱客户端的默认地址,很容易出错,导致无法收发邮件,影响到正常的工作.那么,手动设置 ...

  9. eyoumailserver邮箱服务器与foxmail 邮箱客户端的使用和安装

    2 邮箱服务器 2.1 邮箱服务器的基本概念 邮件的客户端:可以只安装在电脑上的也可以是网页形式的 邮件服务器:起到邮件的接受与推送的作用 邮件发送的协议: 协议:就是数据传输的约束 接受邮件的协议: ...

  10. Latex+英文论文+工具+邮箱客户端不能登录

    表格 \begin{table}[H] % 这里的H表示表格位置订在这个位置 \caption{This is a table caption..\label{tab1}} % 这里写表格描述 \be ...

最新文章

  1. aspose.words 合并相同值的单元格_合并相同的单元格,你用了1小时,同事只要30秒,还支持自动刷新...
  2. maven静态资源导出(Ctrl+C+V)
  3. mysql sql语句 入门_mysql(3)mysql的sql语句入门
  4. 防仿百度图片背景色php,基于jQuery实现仿百度首页换肤背景图片切换代码_jquery...
  5. 金山云服务器内网带宽,性能提升40%!第三代金山云服务器全面覆盖不同企业计算力需求...
  6. 【CCCC】L3-003 社交集群 (30分),并查集模板,map排序
  7. SOA与云计算有多大关联?
  8. 操作系统原理常见面试题总结
  9. 虚拟机用Linux安装软件
  10. POS机交易支付知识点整理
  11. [2018大数据年终总决赛一等奖]金融市场板块划分与轮动规律挖掘与可视化问题
  12. python求15 17 23 65 97的因数_python练习题-答案
  13. CIM是什么?CIM智慧城市建设路径分析
  14. hadoop3.3.1搭建过程遇到的坑
  15. python渲染光线_Python光线追踪
  16. 我平常用计算机玩游戏英语,桌面游戏用英语怎么说
  17. java 双列集合Map 万字详解
  18. 去年写的代码大全笔记(其实是摘记)
  19. xml文件基本格式与解析
  20. WORD之smartart

热门文章

  1. 斯特林公式 (Stirling公式)
  2. IDC中国大型企业SaaS云服务市场:金蝶位居第一
  3. element的上传如何获取路径_element中文件上传
  4. java基于uni-app框架的民宿客房预订系统 小程序
  5. 罗马数字数字1到10对照表
  6. C语言中%d,%o,%f,%e,%x的意义
  7. 为什么用MongoDB而不用Redis
  8. ESP分区和MSR分区下怎么重做GHOST系统
  9. 基于Android NFC的门票系统
  10. 计算机中rom的意思是什么,ROM 是什么意思