文章目录

  • 背景需求
  • 一、imap、pop3是什么?
  • 1. POP3
  • 2. imap
  • 3. 技术选型
  • 二、代码示例
  • 1.imap
  • 2.pop3简单示例
  • 总结



背景需求

每小时定时拉取指定邮箱的未读邮件内容:

内容包括:邮件主题,发送人,收件人,抄送人,邮件时间,邮件正文内容,对应的附件文件列表


经过调研,可使用pop3和imap实现

一、imap、pop3是什么?

1. POP3

POP3协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 。
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

2. imap

IMAP提供webmail 与电子邮件客户端之间的双向通信,客户端的操作都会反馈到服务器上,对邮件进行的操作,服务器上的邮件也会做相应的动作。
同时,IMAP像POP3那样提供了方便的邮件下载服务,让用户能进行离线阅读。IMAP提供的摘要浏览功能可以让你在阅读完所有的邮件到达时间、主题、发件人、大小等信息后才作出是否下载的决定。此外,IMAP 更好地支持了从多个不同设备中随时访问新邮件。

3. 技术选型

生产环境使用imap实现,因为涉及到标记已读未读

二、代码示例

1.imap

几乎每一行都有注释,看注释应该就懂

import email
from email.utils import parseaddr
import imaplib
from email.header import decode_header
import os
import time
import urllib.request

# 邮箱用户名
email_user = ''

# 进入邮箱->设置->账户->开启imap 会生成一个授权码
password = ''

#QQ的imap接收邮件服务器。我用的qq,其他邮箱自查一下
imap_server = 'imap.qq.com'

# 当前目录,用于存放附件文件路径
save_path = os.getcwd()+"/data"

def email_process(email_user, password, imap_server):
    # 这里的服务器根据需要选择
    server = imaplib.IMAP4_SSL(imap_server)
    
    # 登录imap,使用纯文本密码标识客户。 password 将被转码
    server.login(email_user, password)
    
    # 选择邮箱文件夹,没有则创建,此段用来测试,可忽略
    """ destmailbox = 'CaiZiXi'
    rsp, msgs = server.select(destmailbox)
    print(rsp)
    if (rsp == 'NO'):
        server.create(destmailbox)
        print('IMAP: create mail box ' + destmailbox) """
 
    # 邮箱中的文件夹,默认为'INBOX'(收件箱),不需要改
    rsp, inbox = server.select("INBOX")

    # 搜索匹配的邮件,第一个参数是字符集,None默认就是ASCII编码,第二个参数是查询条件
    # 这里的ALL就是查找全部,UNSEEN 为标识未读 SEEN 为已读
    # 生成环境用的是未读UNSEEN,读取完毕设置该邮件为已读,这样下次读取不会重复读取
    type, data = server.search(None, "ALL")

    # 邮件列表,使用空格分割得到邮件索引
    msgList = data[0].split()

	# 附件文件名称,根据实际需要设置
    attachment_files = []

    #遍历所有邮件
    for i in range(0, len(msgList)):

        # 改变邮箱中消息的旗标处理,设置为已读,可放在下载完附近或读取内容使用
        #server.store(msgList[i], '+FLAGS', '\\SEEN')
        
        # server.copy(msgList[i], "CSDN") 测试copy邮件用
        type, datas = server.fetch(msgList[i], '(RFC822)')
        
        # 使用utf-8 解码
        text = datas[0][1].decode('utf8')
        
        # 转化为email.message对象
        msg = email.message_from_string(text)
        
        From = parseaddr(msg.get('from'))[1]  # 发件人
        To = parseaddr(msg.get('To'))[1]  # 收件人
        Cc = parseaddr(msg.get_all('Cc'))[1]  # 抄送人
        Subject = decode_str(parseaddr(msg.get('Subject'))[1])  # 主题

        # 获取邮件时间,格式化收件时间
        date1 = time.strptime(msg.get("Date")[0:24], '%a, %d %b %Y %H:%M:%S')
        # 邮件时间格式转换
        date2 = time.strftime("%Y-%m-%d", date1)
        print(f'发件人:{From};收件人:{To};抄送人:{Cc};主题:{Subject};收件日期:{date1}')

		#这里接收附件和正文内容
        for part in msg.walk():
            file_name = part.get_filename()
            if file_name:
                file_name = decode_str(file_name)
                data = part.get_payload(decode=True)
                #保存附件文件
                att_file = open(os.path.join(save_path, file_name), 'wb')
                attachment_files.append(file_name)
                att_file.write(data)
                att_file.close()
                print(f"附件 {file_name} 下载完成")
            elif not part.is_multipart():
            	#打印会有两个内容,一个纯文本,一个html文本
                print(part.get_payload(decode=True).decode('utf-8'))

"""字符编码转换"""
def decode_str(s):
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
        return value


if __name__ == '__main__':
    print("start")
    email_process(email_user, password, imap_server)
    print("end")

建议对着官方网站来理解 https://docs.python.org/zh-cn/3.7/library/imaplib.html?highlight=imaplib#imap4-example 里面有最简单的示例

2.pop3简单示例

代码如下(示例):

# 导入库——qq邮箱测试,其他邮箱略有差异
import poplib
import email
import datetime
import time
import traceback
import sys
import telnetlib
import zipfile
import os
import shutil
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr

# 输入邮件地址, 口令和POP3服务器地址:
email_user = ''

# 此处密码是授权码,用于登录第三方邮件客户端
password = ''

pop3_server = 'pop.qq.com'

# 授权码登录邮箱
def email_login(email_user, password, pop3_server):
    # 连接到POP3服务器,有些邮箱服务器需要ssl加密,可以使用poplib.POP3_SSL
    telnetlib.Telnet('pop.qq.com', 995)
    server = poplib.POP3_SSL(pop3_server, 995, timeout=50)

    # server=poplib.POP3(pop3_server,110,timeout=10)
    # 可以打开或关闭调试信息
    #server.set_debuglevel(1)

    # 身份认证:
    server.user(email_user)
    server.pass_(password)

    # 返回邮件数量和占用空间:
    print('Messages: %s. Size: %s' % server.stat())

    # list()返回所有邮件的编号:
    resp, mails, octets = server.list()

    return mails, server

def decode_str(str_in):
    """字符编码转换"""
    value, charset = decode_header(str_in)[0]
    if charset:
        value = value.decode(charset)
    return value
   
def save_att_file(msg, save_path):
    """附件下载函数"""
    for part in msg.walk():
        file_name = part.get_filename()
        # contentType = part.get_content_type()
        attachment_files =[]
        if file_name:
            file_name = decode_str(file_name)
            data =  part.get_payload(decode=True)
            # print("emailcontent:\r\n"+data.decode('unicode_escape'))
            att_file = open(os.path.join(save_path,file_name), 'wb')
            attachment_files.append(file_name)
            att_file.write(data)
            att_file.close()
            print(f"附件 {file_name} 下载完成")

def main(inday):
    # 遍历所有邮件
    for i in range(4,len(mails)+1):
        resp,lines,octets = server.retr(i)
        
        msg_content=b'\r\n'.join(lines).decode('unicode_escape')

        # 解析邮件:
        msg = Parser().parsestr(msg_content)
        #print(msg)

        From = parseaddr(msg.get('from'))[1]#发件人
        To = parseaddr(msg.get('To'))[1]#收件人
        Cc = parseaddr(msg.get_all('Cc'))[1]#抄送人
        Subject = decode_str(parseaddr(msg.get('Subject'))[1])#主题
       
        # 获取邮件时间,格式化收件时间
        date1 = time.strptime(msg.get("Date")[0:24],'%a, %d %b %Y %H:%M:%S')
        # 邮件时间格式转换
        date2 = time.strftime("%Y-%m-%d %H:%M:%S",date1)
        """ if date2 <= "2022-09-18":
            continue

        print(Subject)
        print(date2)
        break """
        print(f'发件人:{From};收件人:{To};抄送人:{Cc};主题:{Subject};收件日期:{date2}')

        # 主题和日期验证所需邮件
        if ("iam" in Subject)&(date2 == inday):
            save_att_file(msg, save_path)
      
# 今天日期
today = datetime.date.today()
inday = today.strftime('%Y-%m-%d')

# 昨天日期
yesterday = (today - datetime.timedelta(days=1)).strftime('%Y-%m-%d')

#当前目录
save_path = os.getcwd()

# 登录获取邮件列表
mails,server = email_login(email_user,password,pop3_server)

# 下载主程序
main(inday)

总结

日常工作中用到的PHP居多,python少用,有啥不对的可以讨论