文章目录
- 背景需求
- 一、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少用,有啥不对的可以讨论