Python 用IMAP接收邮件

1、简介
IMAP(Internet Message Access Protocol),这个协议与POP同样,也是从邮件服务器上下载邮件到本机,不过IMAP比POP的功能要更增强大些,IMAP除支持POP全部功能外,还支持如下功能:php

  • 多个邮件文件夹(收件箱、发件箱、垃圾邮件...)
  • IMAP服务器上进行标记如:Seen, Replied, Read, Deleted
  • 在服务器端的文件夹之间拷贝和移动邮件
  • ...

  在IMAP的各版本中,最流行的是IMAP4。咱们就使用IMAP4
  因为,我须要搜索是否有未读邮件,也就是利用邮件服务器的Flag,因此IMAP是很是适合的,个人程序就利用的是IMAP。
  在Python的标准库包含一个imaplib模块,能够利用这个模块。可是,这个模块的缺陷就是把大量解析的工做留给客户端程序员。
2、IMAPClient
  IMAPClient是一个很是受欢迎的IMAPCLient包,这个模块不在标准Python库中。IMAPClient包是由一名叫作Menno Smits的Python程序员编写的。官网网址:http://imapclient.freshfoo.com/。能够在这里查看手册文档。这个包是基于标准库imaplib,不过要更强大。下面咱们来介绍下怎样安装。
1. virtualenv
  说实话,我本人对virtualenv的理解也不透彻,以字面上来理解为虚拟环境。能够把一些模块、包安装在特定的virtualenv里,一旦安装了virtualenv,你就建立任意多个自组织的虚拟python环境,在这个环境里,能够安装、下载包。
  好吧,废话就很少说,直接说方法。
  这里是virtualenv的详细说明,上面介绍了很是详细的安装方法,按照我本身的经验,能够简化为如下步骤:python

$ [sudo] pip install virtualenv
$ [sudo] pip install https://github.com/pypa/virtualenv/tarball/develop
$ curl -O https://pypi.python.org/packages/source/v/virtualenv/ virtualenv-X.X.tar.gz
$ tar xvfz virtualenv-X.X.tar.gz
$ cd virtualenv-X.X
$ [sudo] python setup.py installgit

  注意,上面下载的 virtualenv-X.X.tar.gz 中的X是型号,须要把它改为数字,详细版本类型能够参考:https://pypi.python.org/packages/source/v/virtualenv/程序员

  这样,virtualenv已经安装好。下面须要建立虚拟环境实例,步骤以下:
$ virtualenv --no-site-packages myenv
$ cd myenv
2. 安装IMAPClient
  myenv 为本身定义的虚拟环境的名字。这样,咱们已经在myenv里面,接下来就可一安装IMAPClient包了。步骤以下:
$ sudo pip install imapclient
$ python -c 'import imapclient'github

  此时,能够在python下使用imapclient模块,可是不能在python3下使用,在网上查了一些资料,尤为是看了上面的那个介绍virtualenv的网页,没找到有用的,可是,回头发现,这个imapclient是好使的了,不用进入gmapenv,直接使用便可,got it!
  注意,上面用到了pip工具,若是没有的话必定要安装啊。
$ sudo apt-get install pipweb

3、开始正式学习IMAP
1. 由于可能会出现中文,所以在程序的最上面,必须加上以下代码:
apache

#-*- encoding: utf-8 -*-
#-*- encoding: gbk -*-

2. 所需模块服务器

import getpass, email, sys
from imapclient import IMAPClient

3. 链接服务、登陆帐户
  这一步也没什么好讲的。代码以下:curl

# 经过如下方式链接smtp服务器,没有考虑异常状况,详细请参考官方文档
c = IMAPClient(hostname = 'imap.gmail.com', ssl= True) 
try:
    c.login(username, passwd) #登陆我的账号
except c.Error:
    print('Could not log in')
    sys.exit(1)

4. 进入收件箱,查看未读邮件函数

c.select_folder('INBOX', readonly = True) 
result = c.search('UNSEEN')

  利用select_folder()函数进行文件夹,'INBOX'为收件箱,readonly = True 代表只读并不修改任何信息
  利用search()函数选择想要的邮件,'UNSEEN'是邮件的flag,关于邮件的flag就不特别说明了,返回邮件的message-id
5. 有了未读邮件的ID(result),下面利用fetch()函数将邮件取来(下载到本机)

msgdict = c.fetch(result, ['BODY.PEEK[]'] )

  经过fetch()函数取得邮件内容,fetch()的详细介绍请见这里
      fetch(self, message, data) 其中self参数可忽略,message为message_id, data 的做用是抓取message中的哪些部分。  官方文档中没有给出data的其余可选的参数,我一开始怎么都不找到,最终在stackoverflow中进行提问,一位大哥把这个文档介绍给我,在 6.4.5 FETCH Command 。这里面很是详细的介绍了各个函数的各类细节,固然也能够查到data其余可选的参数 6.4.5 表示的是原书的节。特别感谢这位哥们,人类的力量是无穷的啊!

  咱们只须要'BODY.PEEK[]'便可。
6. 已经把邮件取出,下面开始解析邮件

for message_id, message in msgdict.items():
e = email.message_from_string(message['BODY[]']) # 生成Message类型

7. 获得的 e 即为Message类型的邮件,先面开始将又将中解析出'From', 'Subject'

  还记得上面在POP讲解中,咱们遇到的不能显示中文的问题吗?在IMAP中仍会出现,下面就讲解解决办法
  因为'From', 'Subject' header有可能有中文,必须把它转化为中文,在这个点上,耽误了我很长时间,最终在网上查到了一个方法:http://blog.csdn.net/bonnshore/article/details/8729984 虽然不是很明白,可是能把问题解决就是王道。代码以下:

subject = email.header.make_header(email.header.decode_header(e['SUBJECT'])) #必须保证包含subject
mail_from = email.header.make_header(email.header.decode_header(e['From']))

8. 从Message e中解析出content正文
  同上一篇的POP同样,根据get_payload()返回的不一样类型,选择解析方法,代码以下:

maintype = e.get_content_maintype()
if maintype == 'multipart':
    for part in e.get_payload():
    if part.get_content_maintype() == 'text':
        mail_content = part.get_payload(decode=True).strip()
elif maintype == 'text':
    mail_content = e.get_payload(decode=True).strip()

# 此时,须要把content转化成中文,利用以下方法:    
try:
    mail_content = mail_content.decode('gbk')
except UnicodeDecodeError:
    print('decode error')
    sys.exit(1)

9. 至此,咱们已经完成了查看是否有未读邮件。若是有的话将未读邮件的'From', 'Subject', content解析出来。正如上面完成的 mail_from, subject, mail_content同样,如今能够完美的显示,即便有中文!

4、完整代码

#-*- encoding: utf-8 -*-
#-*- encoding: gbk -*-

# 由于可能会用到中文,因此必须有上面的这两句话

# 引入模块及IMAPClient类
import getpass, email, sys
from imapclient import IMAPClient

hostname = 'imap.gmail.com' #gmail的smtp服务器网址
username = 'myUserName@gmail.com'
passwd = '***'

c = IMAPClient(hostname, ssl= True) # 经过一下方式链接smtp服务器,没有考虑异常状况,详细请参考官方文档
try:
    c.login(username, passwd) #登陆我的账号
except c.Error:
    print('Could not log in')
    sys.exit(1)
else:
    c.select_folder('INBOX', readonly = True) 
# 利用select_folder()函数进行文件夹,'INBOX'为收件箱,readonly = True 代表只读并不修改任何信息
result = c.search('UNSEEN') msgdict = c.fetch(result, ['BODY.PEEK[]'] ) # 如今已经把邮件取出来了,下面开始解析邮件 for message_id, message in msgdict.items(): e = email.message_from_string(message['BODY[]']) # 生成Message类型
     # 因为'From', 'Subject' header有可能有中文,必须把它转化为中文 subject = email.header.make_header(email.header.decode_header(e['SUBJECT'])) mail_from = email.header.make_header(email.header.decode_header(e['From']))      
     # 解析邮件正文 maintype = e.get_content_maintype() if maintype == 'multipart': for part in e.get_payload(): if part.get_content_maintype() == 'text': mail_content = part.get_payload(decode=True).strip() elif maintype == 'text': mail_content = e.get_payload(decode=True).strip()
     # 此时,须要把content转化成中文,利用以下方法: try: mail_content = mail_content.decode('gbk') except UnicodeDecodeError: print('decode error') sys.exit(1) else: print('new message') print('From: ', mail_from) print('Subject: ', subject) getstr = input('if you wanna read it, input y: ') if getstr.startswith('y'): print('-'*10, 'mail content', '-'*10) print(mail_content.replace('<br>', '\n')) print('-'*10, 'mail content', '-'*10) finally:
  c.logout()

5、总结
  至此,咱们已经学习了利用Python编写邮件服务的全部很是基本的内容,因为个人需求不是很高,目标不是作成一个功能强大的邮箱客户端,因此诸如:MIME、附件、图片等功能都没有学习,固然也没有介绍。
  由于咱们如今接收的邮件,大多数都是MIME格式的,不过上文的包含了点解析MIME格式邮件的代码。详细请参考《Foundations of Python3 Network Programming. 2nd Edition》Chaper E-mail Composition and Decoding。

相关文章
相关标签/搜索