xu773

背景:需要读取邮件,对提交的申请进行处理,然后回复邮件。非常繁琐,想要利用python实现自动处理。

第一步:通过IMAP协议读取未读邮件ID;解析标题和邮箱地址。

第二步:数据处理,标题提取出账号;不符合规范的手动处理;提取标题符合规范的邮件对应邮箱地址。

第三步:通过SMTP协议批量发送邮件。

 

python3 imaplib库的官方文档
https://docs.python.org/3/library/imaplib.html?highlight=imaplib#module-imaplib
python3 email库的官方文档
https://docs.python.org/3/library/email.html?highlight=email#module-email

 

一、通过IMAP协议读取文件,并提取标题和发件箱信息。

 

  IMAP(Internet Mail Access Protocol,Internet消息访问协议)是斯坦福大学在1986年开发的一种邮件获取协议。IMAP协议运行在TCP/IP协议之上,使用的端口是143。常用的版本是IMAP4。

  它与POP3协议的主要区别是用户可以:
  •   不用把所有的邮件全部下载,可以通过客户端直接对服务器上的邮件进行操作。
  •   有选择的从邮件服务器接收邮件的功能、基于服务器的信息处理功能和共享信箱功能。
  •   通过浏览信件头来决定是否收取、删除和检索邮件的特定部分
  •   在服务器上创建或更改文件夹或邮箱。
  •   支持脱机操作模式,不同于POP3,它不会自动删除在邮件服务器上已取出的邮件
  •   还支持联机操作和断连接操作,将邮件服务器作为“远程文件服务器”进行访问,更加灵活方便。
  •   IMAP4支持多个邮箱。
  IMAP4的这些特性非常适合在不同的计算机或终端之间操作邮件的用户(例如你可以在手机、PAD、PC上的邮件代理程序操作同一个邮箱),以及那些同时使用多个邮箱的用户。
 
1.连接邮箱服务器并登录。
 1 # -*- coding:utf-8 -*-
 2 # 登录邮箱并发送邮件。
 3 import imaplib
 4 import email
 5 from email.header import decode_header
 6 
 7 \'\'\'第一部分:收件IMAP4********************************************\'\'\'
 8 \'\'\'登录邮箱IMAP4==========================================================\'\'\'
 9 from_addr = \'a@b.com\'  # 发件邮箱
10 password = \'password\'  # 邮箱密码(或者客户端授权码)
11 imap_server = \'imap.qiye.163.com\'
12 
13 try:
14     email_server = imaplib.IMAP4_SSL(imap_server, 993)  #网易企业邮箱服务器及SSL端口
15     print("imap4 服务器连接成功")
16 except:
17     print("imap4 服务器连接失败")
18     exit(1)
19 
20 try:
21     email_server.login(from_addr, password)
22     print("imap4 账号密码正确,登录成功")
23 
24 except:
25     print("imap4 账号密码不正确,登录失败")
26     exit(1)

2.获取未读邮件ID,解析邮件标题和邮箱地址。

 1 \'\'\' 邮箱中收到的未读邮件的数量==========================================================\'\'\'
 2 email_server.select()
 3 #未读邮件封数 email_unseen_count
 4 email_unseen_count = len(email_server.search(None, \'UNSEEN\')[1][0].split())  #所有未读邮件
 5 print(\'未读邮件一共有:\',email_unseen_count,\'\')
 6 #得到所有未读邮件标号ID的byte格式 email_unseen_id_byte [b\'5255\', b\'5256\', b\'5257\']
 7 email_unseen_id_byte = email_server.search(None, \'UNSEEN\')[1][0].split()  #[b\'5255\', b\'5256\', b\'5257\']
 8 
 9 #得到所有未读邮件标号将byte格式转为为str email_unseen_id [\'5255\', \'5256\', \'5257\', \'5258\']
10 email_unseen_id = []
11 count_byte = 0
12 for row in email_unseen_id_byte:
13     email_unseen_id.append(row.decode(\'utf-8\'))
14 print(email_unseen_id)
15 
16 \'\'\'读取邮件标题,地址=========================================================\'\'\'
17 # 通过fetch(index)读取第index封邮件的内容
18 sub_list = []
19 addr_list = []
20 
21 #对每一封邮件进行处理
22 for a in email_unseen_id:
23     # 获取邮件主题和地址信息,byte格式
24     typ, email_content = email_server.fetch(f\'{a}\'.encode(), \'(RFC822)\')
25     mail_text = email_content[0][1]
26     msg = email.message_from_bytes(mail_text)
27     subject = msg[\'Subject\']
28     email_from = msg[\'from\']
29     subdecode = decode_header(subject)   #[(b\'\xc9\xed\xdd\xc8\xcf\xd6\xbb\xd8\xcc\xc2\xeb\', \'gb18030\')]
30     from_decode = decode_header(email_from)  # [(b\'"\', None), (b\'\xd0\xa1\xe3\', \'gb18030\'), (b\'" <3825@qq.com>\', None)]
31     print(from_decode)
32 
33     #将邮件信息由byte格式转换为str
34     if subdecode[0][1] == None:    #[(b\'"\', None), (b\'\xd8\xafA1\xc9\xb5\xb9\xcf\', \'gb18030\'), (b\'" <970@qq.com>\', None)]
35         print(subdecode[0][1])
36 
37     else:
38         addr_list.append(addr_list.append(from_decode[2][0].decode(\'utf-8\')))
40         sub_list.append(subdecode[0][0].decode(subdecode[0][1]))  #<class \'str\'>
41 
42 print(\'sub_list:\', sub_list) #[\'找回\', \'杨 1702\']
43 print(\'addr_list:\', addr_list)   # [\'" <385@qq.com>\', \'" <51@qq.com>\']

3.关闭IMAP连接

1 \'\'\'关闭IMAP4 select=========================================================\'\'\'
2 # 关闭select
3 email_server.close()
4 # 关闭连接
5 email_server.logout()

二、数据处理:提取能处理的账号和邮箱地址

1.提取标题中含有8位或10位的数字,其余用X标记

 1 import re # 使用正则表达式提取数字。 https://blog.csdn.net/qq_38486203/article/details/80309478
 2 import pandas as pd
 3  
 5 \'\'\'提取账号=============================================\'\'\'
 6 sub_op = []
 7 addr_op = []
 8 
 9 sub_op_f = []
10 addr_op_f = []
11 
12 count = 0
13 count_f = 0
14 
15 for a in sub_list:
16     if re.findall(r\'\d+\',a) == []:
17         sub_op_str = \'x\'
18     else:
19         sub_op_str_num = str(re.findall(r\'\d+\',a))[2:-2]
20         #选出8位或10位账号
21         if len(sub_op_str_num) == 8 or len(sub_op_str_num) == 10:
22             sub_op_str = sub_op_str_num
23         else:
24             sub_op_str = \'x\'
25     sub_op.append(sub_op_str)
26 
27 print("邮件主题中的账号为:",sub_op,\';\') #[\'x\', \'1700000000\', \'x\']

 

2.提取有效邮件对应的邮箱

\'\'\'提取邮箱地址=============================================\'\'\'
for b in addr_list:
    addr_op_str = b.strip()[3:-1]  #去掉头尾 [\'" <38@qq.com>\', \'" <31@qq.com>\']
    addr_op.append(addr_op_str)

#print(addr_op)   #[\'38@qq.com\', \'31@qq.com\', \'a1@qq.com\']

\'\'\'删除主题用X标记的账号和地址=============================================\'\'\'
for c in sub_op:
    if c == \'x\':
        count = count+1
    else:
        sub_op_f.append(sub_op[count])
        addr_op_f.append(addr_op[count])
        count = count+1

print("邮件中地址为:",addr_op_f)  # <class \'list\'>

3.利用pandas读取并保存为csv备查

 1 \'\'\'把这一批次所有读取的账号地址和处理的账号地址都导出到EXCLE存档备查=============================================\'\'\'
 2 import pandas as pd
 3 # 读取所有未读主题,账号,地址并保存
 4 data_unseen = [sub_list,sub_op,addr_op]
 5 data_unseen1 = pd.DataFrame(data_unseen)
 6 data_unseen1.to_csv(\'data_unseen.csv\',sep=\',\', header=True, index=True,encoding=\'utf_8_sig\')
 7 
 8 # 读取所有已处理邮件的主题,账号,地址并保存
 9 data_op = [sub_list,sub_op_f,addr_op_f]
10 data_op1 = pd.DataFrame(data_op)
11 data_op1.to_csv(\'data_op.csv\',sep=\',\', header=True, index=True,encoding=\'utf_8_sig\')

三、发送邮件

1.连接SMTP服务器并登录

 1 # 登录邮箱并发送邮件。
 2 from email.mime.text import MIMEText
 3 from email.header import Header
 4 import smtplib
 5 
 6 #登录邮箱
 7 smtp_server = \'smtp.qiye.163.com\'  # 企业邮箱地址,若是个人邮箱地址为:smtp.163.com
 8 server = smtplib.SMTP_SSL(smtp_server, 994)  # 第二个参数为默认端口为25,这里使用ssl,端口为994
 9 from_addr = \'a@b.com\'  # 发件邮箱
10 password = \'password\'  # 邮箱密码(或者客户端授权码)
11 
12 try:
13     print(\'开始登录\')
14     server.login(from_addr, password)  # 登录邮箱
15     print(\'登录成功\')
16 except Exception as e:
17     print(\'Error:\', e)

2.发送邮件并退出

 1 print("邮件开始发送")
 2 
 3 message = \'\'\'您好,这是一封测试邮件\'\'\'
 6 msg = MIMEText(message, \'plain\', \'utf-8\')
 7 
 8 msg[\'Subject\'] = Header("回复:测试", \'utf-8\')
 9 msg[\'From\'] = Header(\'a@b.com\')
10 
11 to_addr_list = [\'a@qq.com\']
13 
14 try:
15     for to_addr in to_addr_list:
16         msg[\'To\'] = Header(to_addr, \'utf-8\')
17         server.sendmail(from_addr, to_addr, msg.as_string())  # 将msg转化成string发出
18     print("邮件发送成功")
23 
24 except Exception as e:
25     print(\'Error:\', e)
26 
27 server.quit()

四、小结

1.在功能上实现了批量处理未读邮件,但是需要分别执行对应的代码,比较啰嗦,计划后续利用图形界面的方式进行点击处理。

2.当处理的数据过多时,发现部分163或qq邮箱的邮件标题只有两个参数,执行 from_decode[2][0].decode(\'utf-8\') 会报错超出list的定义范围。所以需要多一个判断 len,不同的长度,取的值不一样。

3.越往下做,要解决的业务上的细节问题越多。

 
 
 

分类:

技术点:

相关文章: