sdk/qq_mail/163amil.py

189 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# POP3Post Office Protocol 3即邮局协议的第3个版本
#是电子邮件的第一个离线协议标准。该协议把邮件下载到本地计算机,
#不与服务器同步,缺点是更易丢失邮件或多次下载相同的邮件。
import poplib
# 引入用来解析邮件相关信息的模块
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
#引入相关时间库
from datetime import datetime
#引入专门处理时间和日期的模块arrow是一个轻量级Python库
import arrow
# 输入自己163的邮箱地址。
user_email_address = '17279617782@163.com'
# 邮箱的授权码,注意:不是登录密码
user_password = 'RDbwq3yRppmDn9x6'
# 这个是163邮箱的pop3的服务器地址各个公司的邮箱平台的POP3的服务器地址都是不同的自己网上查询下即可
#例如qq邮箱的pop3服务器地址是pop.qq.com
pop_server_host = 'pop.163.com'
# 邮箱对应的pop服务器的监听端口
#如果设置POP3的SSL加密方式连接的话则端口为995否则就是端口为110
pop_server_port = 995
def connect_email_by_pop3():
try:
# 连接pop服务器。如果没有使用SSL将POP3_SSL()改成POP3(),且监听端口改为110即可
email_server = poplib.POP3_SSL(host=pop_server_host, port=pop_server_port, timeout=10)
print("连接pop服务器-------正常,开始验证用户邮箱")
except:
print("连接pop服务器-------异常,退出")
exit(1)
try:
# 验证用户邮箱
email_server.user(user_email_address)
print("用户邮箱验证-------正常,开始验证邮箱授权码")
except:
print("用户邮箱验证-------异常,退出")
exit(1)
try:
# 验证邮箱密码是否正确,注意不是登录密码,是授权码
email_server.pass_(user_password)
print("邮箱授权码验证-------正常,开始接受邮箱以及附件")
except:
print("邮箱授权码验证-------异常,退出")
exit(1)
# 开始处理邮箱相关信息
parse_email_server(email_server)
def parse_email_server(email_server):
resp, mails, octets = email_server.list()
num, total_size = email_server.stat()
print("邮件数量为:" + str(num))
# mails存储了邮件编号列表
index = len(mails)
# 倒序遍历邮件
for i in range(index, 0, -1):
# 倒序遍历邮件,这样取到的第一封就是最新邮件
resp, lines, octets = email_server.retr(i)
# lines存储了邮件的原始文本的每一行,
# 邮件的原始文本:# lines是邮件内容列表形式使用join拼成一个byte变量
msg_content = b'\r\n'.join(lines).decode('utf-8')
# 解析邮件:
msg = Parser().parsestr(msg_content)
# 邮件时间,解析时间格式
mail_datetime = parse_mail_time(msg.get("date"))
max_mail_time_str = arrow.get(mail_datetime).format("YYYY-MM-DD HH:mm")
# 这个可以作为根据时间进行邮件的过滤解析,这个把时间写死判断,比较局限,可以在第一个接收时,把最新的邮件接收时间写入到自定义的文件中,
# 等第二次接收邮件时,再取文件中的时间,进行判断,用于过滤
# if (max_mail_time_str > "2020-01-01 00:00:00"):
# continue
print("邮件接收时间为:" + max_mail_time_str)
# 解析邮件具体内容,包括正文,标题,和附件
parser_content(msg, 0)
# 别忘记退出
email_server.quit()
def parser_content(msg, indent):
if indent == 0:
# 邮件的From, To, Subject存在于根对象上:
# 调用解析邮件头部内容的函数
parser_email_header(msg)
# 下载附件
for part in msg.walk():
file_name = part.get_filename() # 获取附件名称类型
if file_name is None:
continue
# 说明不是文本,则作为附件处理
filename = decode_str(file_name) # 对附件名称进行解码
data = part.get_payload(decode=True) # 下载附件
att_file = open('D:/pyproject/box/qq_mail/attachments' + filename, 'wb') # 在指定目录下创建文件注意二进制文件需要用wb模式打开
att_file.write(data) # 保存附件
att_file.close()
print("附件:" + filename + "保存成功!")
if (msg.is_multipart()):
# 如果邮件对象是一个MIMEMultipart,
# get_payload()返回list包含所有的子对象:
parts = msg.get_payload()
for n, part in enumerate(parts):
# 递归打印每一个子对象:
return parser_content(part, indent + 1)
else:
# 解析正文
content_type = msg.get_content_type()
if content_type == 'text/plain' or content_type == 'text/html':
# 纯文本或HTML内容:
content = msg.get_payload(decode=True)
# 要检测文本编码:
charset = guess_charset(msg)
if charset:
content = content.decode(charset)
print('%s正文内容为: %s' % (' ' * indent, content))
# 解析邮件
def parser_email_header(msg):
# 解析邮件标题
subject = msg['Subject']
value, charset = decode_header(subject)[0]
if charset:
value = value.decode(charset)
print('邮件标题: {0}'.format(value))
# 解析发送人信息
hdr, addr = parseaddr(msg['From'])
# name 发送人邮箱名称, addr 发送人邮箱地址
name, charset = decode_header(hdr)[0]
if charset:
name = name.decode(charset)
print('发送人邮箱名称: {0},发送人邮箱地址: {1}'.format(name, addr))
# 解析接收人信息
hdr, addr = parseaddr(msg['To'])
# name 发送人邮箱名称, addr 发送人邮箱地址
name, charset = decode_header(hdr)[0]
if charset:
name = name.decode(charset)
print('接收人邮箱名称: {0},接收人邮箱地址: {1}'.format(name, addr))
# 解码
def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
# 猜测字符编码
def guess_charset(msg):
# 先从msg对象获取编码:
charset = msg.get_charset()
if charset is None:
# 如果获取不到再从Content-Type字段获取:
content_type = msg.get('Content-Type', '').lower()
for item in content_type.split(';'):
item = item.strip()
if item.startswith('charset'):
charset = item.split('=')[1]
break
return charset
# 邮件时间处理函数
def parse_mail_time(mail_datetime):
GMT_FORMAT = "%a, %d %b %Y %H:%M:%S"
GMT_FORMAT2 = "%d %b %Y %H:%M:%S"
index = mail_datetime.find(' +0')
if index > 0:
mail_datetime = mail_datetime[:index] # 去掉+0800
formats = [GMT_FORMAT, GMT_FORMAT2]
for ft in formats:
try:
mail_datetime = datetime.strptime(mail_datetime, ft)
return mail_datetime
except:
pass
raise Exception("邮件时间格式解析错误")
# 比较规范写法,象征着程序入口
if __name__ == "__main__":
connect_email_by_pop3()