当前位置:   article > 正文

python 邮箱自动化操作(1) 邮件的自动获取 imapclient 非常详细!有范例!!_python imap

python imap

版本

python 3.8

imapclient:3.0.0 

注意: 这里是以腾讯企业邮箱为例,不同的邮箱可能会有不同的编码格式,就可能会产生错误。

邮件协议概述

  1. SMTP (Simple Mail Transfer Protocol)

    • SMTP 是用于发送电子邮件的标准协议。
    • 客户端使用 SMTP 将邮件发送到邮件服务器。
    • SMTP 客户端连接到 SMTP 服务器的 25 号端口。
    • SMTP 协议通常用于将邮件从发送方传输到接收方的邮件服务器。
  2. POP3 (Post Office Protocol version 3)

    • POP3 是用于从邮件服务器上获取邮件的协议。
    • 客户端使用 POP3 从邮件服务器下载邮件到本地计算机。
    • POP3 客户端连接到 POP3 服务器的 110 号端口。
    • POP3 协议通常会将邮件从服务器上下载到客户端,并在下载后从服务器上删除邮件。
  3. IMAP (Internet Message Access Protocol)

    • IMAP 也是用于从邮件服务器上获取邮件的协议,与 POP3 类似,但提供了更多的功能。
    • IMAP 允许客户端在多个设备上同步查看邮件,因为邮件仍然保留在服务器上。
    • IMAP 客户端连接到 IMAP 服务器的 143 号端口。
    • IMAP 协议通常更适合需要在多个设备上访问邮件的用户,因为它允许在所有设备上同步邮件状态。

这里列举了三种协议,其中SMTP用于发送邮件,POP3和IMAP用于获取邮件,由于IMAP更强大,所有本文的邮件获取也是基于IMAP协议。

从邮箱获取邮件 (标题、内容、附件等)

python虽然自带imaplib这个包,但用起来比较复杂,所以在这一部分,本文使用imapclient,这是一个用于 IMAP 客户端的第三方库,提供了更高级的功能,例如搜索、标记、文件夹管理等,它比标准库中的 imaplib 更易于使用。

1. 邮箱登录

  1. from imapclient import IMAPClient
  2. # 邮箱登录
  3. email_address = 'xxxx@xxxx.com' # 邮箱地址
  4. password = 'xxxxxx' # 密码
  5. # 邮箱服务器信息
  6. s_mail = IMAPClient('imap.exmail.qq.com') # HOST = "imap.host.com"
  7. s_mail.login(email_address, password)

2. 选择邮箱 select_folder

就是选择如下所示:

可以先查看邮箱文件夹

选择邮箱文件夹

  1. # 选择邮箱
  2. s_mail.select_folder(folder='inbox', readonly=True) # 这里folder也可以选择 已发送等

运行结果:

这里可以看到,选择不同邮箱会收到不同的返回结果,返回的结果是字典格式的,一般不会用到,这里也没有去赋值。

3. 邮件筛选 search

在选择好邮箱之后,比如收件箱,会拿到大量的邮件,search我看代码可以根据标题、正文、时间、标记(‘SEEN’, 'UNSEEN', 'Flagged')等,但是实际上无法通过标题和正文检索,我想可能原因是跟邮箱编码格式有关,这里我查了很多资料依旧没有解决,但是可以通过遍历邮件的方法实现。

通过时间区间筛选  这里的时间要转换为datetime的格式  

  1. # 从 20240101 这一天开始
  2. message_ids = s_mail.search(['SINCE', datetime.date(2024, 1, 1)])
  3. # 在 20240101 这一天之前 不包括20240101
  4. message_ids = s_mail.search(['BEFORE', datetime.date(2024, 1, 1)])
  5. # 在某个时间区间
  6. since_date = datetime.datetime.strptime(search_date_since, '%Y%m%d')
  7. before_date = datetime.datetime.strptime(search_date_before, '%Y%m%d')
  8. message_ids = s_mail.search(['SINCE', since_date, 'BEFORE', before_date])

通过多个条件筛选 比如在上面的基础上加一个 “未读”

message_ids = s_mail.search(['SINCE', since_date, 'BEFORE', before_date, 'UNSEEN'])

4. 获取邮件数据 fetch

通过 fetch 方法,可以获取邮件的各种信息,如邮件的正文、发件人、收件人、主题、日期等。

以下是 imapclientfetch 方法的一般用法:

fetch_data = s_mail.fetch(message_ids, ['BODY[]', 'FLAGS', 'INTERNALDATE', 'RFC822.SIZE'])

这里的 message_ids 是一个邮件的序号或 UID 列表,用于指定要检索的邮件。第二个参数是一个列表,包含了你想要检索的邮件属性。常见的邮件属性包括:

  • 'BODY[]': 获取邮件的全部内容,包括头部和正文。
  • 'FLAGS': 获取邮件的标志,如已读、已删除等。
  • 'INTERNALDATE': 获取邮件的内部日期,即邮件的收到时间。
  • 'RFC822.SIZE': 获取邮件的大小。

除了以上列出的属性外,还可以指定其他属性,如 'BODY[HEADER]'(获取邮件的头部)、'ENVELOPE'(获取邮件的信封信息,如发件人、收件人、主题等)等。这里的细则可以查看这篇文章python imap fetch的坑icon-default.png?t=N7T8http://t.csdnimg.cn/qdtYV

一般在使用的时候,可以根据需求选择属性,这样获取的数据量会小一点,速度会更快。

这里以‘BODY[]’举例,目的是介绍获取邮件全部内容后,如何获取邮件中各个属性的信息。

通过fetch(message_ids, ['BODY[]']) 获得是一个字典的格式,可以自行输出查看一下。

数据解析方法:

4.1 获取邮件头部信息

  1. content = s_mail.fetch(uid, ['BODY[]'])[uid][b'BODY[]']
  2. email_content = email.message_from_bytes(content)
  3. # 第一种 解析 邮件头部信息
  4. # 像 收件人、发件人、抄送、标题等 这些都是同样的方式 所以以其中一种举例
  5. # 定义解码函数 (这个)
  6. def __decode_str__(hs):
  7. """
  8. 编码处理
  9. :param hs:
  10. :return:
  11. """
  12. if isinstance(hs, bytes):
  13. hs = hs.decode()
  14. if hs:
  15. # loger.info(" ==== {}".format(hs[0]))
  16. if hs[0] == "=":
  17. s, de = decode_header(hs)[0] # s is bytes de='gbk'
  18. failout = base64.b64encode(s).decode()
  19. s = failout if not de else s.decode(de) # str(s, 'gbk') = s.decode('gbk')
  20. return s
  21. else:
  22. return hs
  23. return ''
  24. # 获取标题
  25. subject = __decode_str__(email_content['Subject'])
  26. '''
  27. 以下都可以通过上述方式获得
  28. 邮件头部信息:
  29. Subject:邮件主题
  30. From:发件人
  31. To:收件人
  32. Date:日期时间
  33. Cc:抄送
  34. Bcc:暗送
  35. Message-ID:消息唯一标识符
  36. In-Reply-To:回复邮件的消息标识符
  37. References:参考消息标识符列表
  38. '''

4.2 获取邮件正文

  1. envelope = s_mail.fetch(uid, ['BODY[]'])[uid][b'BODY[]']
  2. email_content = email.message_from_bytes(content)
  3. # 提取邮件正文内容
  4. if email_content.is_multipart():
  5. for part in email_content.walk():
  6. content_type = part.get_content_type()
  7. if content_type == 'text/plain': # 只提取纯文本正文
  8. body = part.get_payload(decode=True).decode('gbk')
  9. print("邮件正文内容:")
  10. print(body)
  11. break
  12. else:
  13. body = email_content.get_payload(decode=True).decode('gbk')
  14. print("邮件正文内容:")
  15. print(body)

4.3 获取邮件附件

  1. for part in email_content.walk():
  2. fileName = part.get_filename()
  3. fileName = __decode_str__(fileName)
  4. print(fileName)
  5. # 附件下载
  6. for part in email_content.walk():
  7. fileName = part.get_filename()
  8. fileName = __decode_str__(fileName)
  9. if fileName:
  10. with open(fileName, 'wb') as f:
  11. data = part.get_payload(decode=True)
  12. f.write(data)

邮件检索 (遍历)

上述三种方法没有办法直接获取目标邮件的指定信息的功能,由1select_flod,2search两种方法,我们也只可以获得一个范围,在search函数中,可以看到subject字段,但是可能由于邮箱的问题,没有达到通过标题筛选的效果。所以邮件检索的方法,可以理解为在一个范围内遍历邮箱。

当邮箱邮件数很多的时候,这个找到目标邮件的方法会很慢,这里有一个小技巧,就是比如通过标题找到目标邮件时,可以在fetch中选择 'BODY[HEADER]',这样数据量相对较小,速度会稍微快一点。

以下是一个范例 (可以直接使用)

获取一个时间区间内的所有邮件,然后通过标题筛选,再拿到目标附件。

search_data_since、search_date_before: 字符串 like:'20240101'

  1. def get_excel_from_mail(search_date_since, search_date_before, target_subject, target_filename):
  2. # 邮箱登录
  3. print("email login...")
  4. email_address = 'xxx@xxx.com'
  5. password = 'xxxxxxx'
  6. # 邮箱服务器信息
  7. # 搜索邮件
  8. s_mail = IMAPClient('imap.exmail.qq.com')
  9. s_mail.login(email_address, password)
  10. s_mail.select_folder('收件箱', readonly=True)
  11. since_date = datetime.datetime.strptime(search_date_since, '%Y%m%d').date()
  12. # 指定日期范围为since_date到since_date的后一天
  13. next_day = datetime.datetime.strptime(search_date_before, '%Y%m%d').date()
  14. result = s_mail.search(['SINCE', since_date, 'BEFORE', next_day])
  15. print('SINCE', since_date, 'BEFORE', next_day)
  16. for uid in reversed(result): # 优先获取最新的邮件
  17. try:
  18. subject = s_mail.fetch(uid, ['ENVELOPE'])[uid][b'ENVELOPE']
  19. subject = __decode_str__(subject.subject)
  20. print(subject)
  21. if target_subject not in str(subject):
  22. continue
  23. except Exception as e:
  24. print(e)
  25. # print(s_mail.fetch(uid, ['ENVELOPE']))
  26. continue
  27. massageList = s_mail.fetch(uid, ['BODY[]'])
  28. mailBody = massageList[uid][b'BODY[]']
  29. # 邮件内容解析最里面那层是按字节来解析邮件主题内容,这个过程生成Message类型
  30. try:
  31. email_content = email.message_from_string(mailBody)
  32. except TypeError:
  33. email_content = email.message_from_bytes(mailBody)
  34. for part in email_content.walk():
  35. fileName = part.get_filename()
  36. fileName = __decode_str__(fileName)
  37. # print('fileName', fileName)
  38. if fileName == target_filename:
  39. print(' OK Subject = {}'.format(subject))
  40. print('邮件附件下载')
  41. # 附件下载
  42. for part in email_content.walk():
  43. fileName = part.get_filename()
  44. fileName = __decode_str__(fileName)
  45. if fileName == target_filename:
  46. # savefile = os.path.join(dirs_email, fileName)
  47. # with open(savefile, 'wb') as f:
  48. # print('--------savefile')
  49. data = part.get_payload(decode=True) # 获取excel内容 保存文件 -----
  50. # f.write(data)
  51. return data
  52. return False
  53. def __decode_str__(hs):
  54. """
  55. 编码处理
  56. :param hs:
  57. :return:
  58. """
  59. if isinstance(hs, bytes):
  60. hs = hs.decode()
  61. if hs:
  62. # loger.info(" ==== {}".format(hs[0]))
  63. if hs[0] == "=":
  64. s, de = decode_header(hs)[0] # s is bytes de='gbk'
  65. failout = base64.b64encode(s).decode()
  66. s = failout if not de else s.decode(de) # str(s, 'gbk') = s.decode('gbk')
  67. return s
  68. else:
  69. return hs
  70. return ''

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/822949
推荐阅读
相关标签
  

闽ICP备14008679号