Python 之 pop 获取邮件和附件
有些库可能用不上的,大家自行判断吧
import re
import module.UpExcel as moduleExcel
import os
from email.utils import parseaddr, parsedate, getaddresses
from email.header import decode_header, Header
from email.parser import Parser
import xlwings as xw
import time
import email
import datetime
import poplib
import pandas as pd
poplib._MAXLINE = 20480
# 此函数通过使用poplib实现接收邮件
email_address = '****@263.com'
email_password = 'password'
def recv_email_by_pop3(email_address, email_password,interval_day):
# 要进行邮件接收的邮箱。改成自己的邮箱
# email_address = ""
# 要进行邮件接收的邮箱的密码。改成自己的邮箱的密码
# 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启服务:POP3/SMTP服务
# 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 生成授权码
# email_password = ""
# 邮箱对应的pop服务器,也可以直接是IP地址
# 改成自己邮箱的pop服务器;
pop_server_host = "pop.263.net"
# 邮箱对应的pop服务器的监听端口。改成自己邮箱的pop服务器的端口;qq邮箱不需要修改此值
pop_server_port = 110
try:
# 连接pop服务器。如果没有使用SSL,将POP3_SSL()改成POP3()即可其他都不需要做改动
email_server = poplib.POP3(host=pop_server_host, timeout=30, port=pop_server_port)
except:
print("pop3----sorry the given email server address connect time out")
exit(1)
try:
# 验证邮箱是否存在
email_server.user(email_address)
except:
print("pop3----sorry the given email address seem do not exist")
exit(1)
try:
# 验证邮箱密码是否正确
email_server.pass_(email_password)
except:
print("pop3----sorry the given username seem do not correct")
exit(1)
# 邮箱中其收到的邮件的数量
email_count = len(email_server.list()[1])
# list()返回所有邮件的编号:
resp, mails, octets = email_server.list()
# 遍历所有的邮件
for i in range(len(mails), 0, -1):
# 通过retr(index)读取第index封邮件的内容;这里读取最后一封,也即最新收到的那一封邮件
resp, lines, octets = email_server.retr(i)
# lines是邮件内容,列表形式使用join拼成一个byte变量
email_content = b'\r\n'.join(lines)
try:
# 再将邮件内容由byte转成str类型
email_content = email_content.decode('utf-8')
except Exception as e:
print(str(e))
continue
# # 将str类型转换成<class 'email.message.Message'>
# msg = email.message_from_string(email_content)
msg = Parser().parsestr(email_content)
print('------------- 分隔符 ---------------')
# 写入邮件内容到文件
list = []
list = parse_email(list, msg, 0, interval_day)
# 时间判断
nowTime = (datetime.datetime.now()+datetime.timedelta(days=interval_day)
).strftime("%Y-%m-%d") + ' 00:00:00'
if list[0] < nowTime:
email_server.close()
return
if len(list) > 2:
riqi = str(time.strftime("%Y-%m-%d", time.localtime()))
filename = r'D:\AutoEmail\Get\Get' + riqi + '.xlsx'
app = xw.App(visible=False, add_book=False)
wb = app.books.open(filename) # 读入已有工作簿
sht = wb.sheets[0] # 引用活动sheet
info = sht.used_range
nrows = info.last_cell.row
sht.range('A'+str(nrows+1)).value = [list]
# 自动调整表格
# sht.autofit()
info.column_width = 40
sht.range('A1:A'+str(nrows+1)).column_width = 16
# 保存工作簿
wb.save(filename)
wb.close() # 关闭工作簿(程序不能编辑了)----显示的文件不关闭
# app.quit() # 退出
app.kill()
# 关闭连接
email_server.close()
# 下载附件
def get_att(msg):
attachment_files = []
for part in msg.walk():
file_name = part.get_filename() # 获取附件名称类型
contentType = part.get_content_type() # 获取数据类型
mycode = part.get_content_charset() # 获取编码格式
if file_name:
h = Header(file_name)
dh = decode_header(h) # 对附件名称进行解码
filename = dh[0][0]
if dh[0][1]:
filename = decode_str(str(filename, dh[0][1])) # 将附件名称可读化
attachment_files.append(filename)
data = part.get_payload(decode=True) # 下载附件
with open(filename, 'wb') as f: # 在当前目录下创建文件,注意二进制文件需要用wb模式打开
#with open('指定目录路径'+filename, 'wb') as f: 也可以指定下载目录
f.write(data) # 保存附件
print(f'附件 {filename} 已下载完成')
elif contentType == 'text/plain': # or contentType == 'text/html':
# 输出正文 也可以写入文件
data = part.get_payload(decode=True)
content = data.decode(mycode)
print('正文:', content)
print('附件文件名列表', attachment_files)
# 读取信息( indent用于缩进显示:)
def parse_email(list, msg, indent,interval_day):
if indent == 0:
# print('msg:',msg)
# 邮件的From, To, Subject存在于根对象上:
for header in ['Date', 'From', 'To', 'CC', 'Subject']:
value = msg.get(header, '')
# if value:
# 时间
if header == 'Date':
strDate = time.strftime("%Y-%m-%d %H:%M:%S", parsedate(value))
# 获取当日发件
nowTime = (datetime.datetime.now(
)+datetime.timedelta(days=interval_day)).strftime("%Y-%m-%d") + ' 00:00:00'
list.append(strDate)
if strDate[:10] < nowTime:
print('%s%s: %s' % (' ' * indent, header, strDate))
return list
print('%s%s: %s' % (' ' * indent, header, strDate))
# 发件人
elif header == 'From':
# 需要解码Email地址:
hdr, addr = parseaddr(value)
# name = decode_str(hdr)
# strFrom = u'%s <%s>' % (name, addr)
strFrom = u'<%s>' % (addr)
list.append(strFrom)
print('%s%s: %s' % (' ' * indent, header, strFrom))
# 收件人
elif header == 'To':
listTo = []
tos = msg.get_all('to', [])
for to in getaddresses(tos):
to = to[0] + ' <' + to[1] + '>'
hdr, addr = parseaddr(to)
name = decode_str(hdr)
# strTo = u'%s <%s>' % (name, addr)
strTo = u'<%s>' % (addr)
listTo.append(strTo)
strlistto = ''.join(listTo)
# # 需要解码Email地址:
# hdr, addr = parseaddr(value)
# name = decode_str(hdr)
# strTo = u'%s <%s>' % (name, addr)
list.append(strlistto)
print('%s%s: %s' % (' ' * indent, header, strlistto))
# 抄送
elif header == 'CC':
listCc = []
ccs = msg.get_all('cc', [])
for cc in getaddresses(ccs):
cc = cc[0] + ' <' + cc[1] + '>'
hdr, addr = parseaddr(cc)
name = decode_str(hdr)
# strCc = u'%s <%s>' % (name, addr)
strCc = u'<%s>' % (addr)
listCc.append(strCc)
strlistCc = ''.join(listCc)
if strlistCc == '':
strlistCc = '空'
# # 需要解码Email地址:
# hdr, addr = parseaddr(value)
# name = decode_str(hdr)
# strCc = u'%s <%s>' % (name, addr)
list.append(strlistCc)
print('%s%s: %s' % (' ' * indent, header, strlistCc))
# 主题
elif header == 'Subject':
# 需要解码Subject字符串:
strSubject = decode_str(value)
list.append(strSubject)
print('%s%s: %s' % (' ' * indent, header, strSubject))
if (msg.is_multipart()):
# 如果邮件对象是一个MIMEMultipart,
# get_payload()返回list,包含所有的子对象:
parts = msg.get_payload()
for n, part in enumerate(parts):
# 递归打印每一个子对象:
parse_email(list, part, indent + 1,interval_day)
return list
else:
for part in msg.walk(): # 遍历所有payload
# 邮件对象不是一个MIMEMultipart,
# 就根据content_type判断:
content_type = msg.get_content_type()
file_name = part.get_filename()
if content_type == 'text/plain' or content_type == 'text/html':
if len(list) < 6:
# 纯文本或HTML内容:
content = msg.get_payload(decode=True)
# 要检测文本编码:
charset = guess_charset(msg)
if charset:
try:
content = content.decode(charset)
except:
content = content.decode("gb2312", errors='ignore')
print('%sText: %s' % (' ' * indent, content))
list.append('text:' + content.replace(' ',
'').replace('\n', '').replace('\r', '')[:300])
if file_name:
h = email.header.Header(file_name)
dh = email.header.decode_header(h) # 对附件名称进行解码
filename = dh[0][0]
if dh[0][1]:
filename = decode_str(str(filename, dh[0][1])) # 将附件名称可读化
#filename = filename.encode("utf-8")
data = part.get_payload(decode=True) # 下载附件
riqi = str(time.strftime("%Y-%m-%d", time.localtime()))
attfileadd = 'D:\\AutoEmail\\Att\\Get\\'+riqi
if not os.access(attfileadd, os.X_OK):
os.mkdir('D:\\AutoEmail\\Att\\Get\\' + './'+riqi+'')
with open(attfileadd + '\\' + filename, 'wb') as f: # 在当前目录下创建文件,注意二进制文件需要用wb模式打开
f.write(data) # 保存附件
print('%sAtt: %s' % (' ' * indent, filename))
list.append(filename)
# else:
# # 不是文本,作为附件处理:
# print('%sAttachment: %s' % (' ' * indent, content_type))
# list.append('Attachment:' + content_type)
return list
# 解码
def decode_str(s):
value, charset = decode_header(s)[0]
# if charset or value[:2]=='Re':
try:
value = value.decode(charset)
except:
try:
value = value.decode("gb2312", errors='ignore')
except:
pass
return value
# 猜测字符编码
def guess_charset(msg):
try:
# 先从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
except:
pass
smtplib 发送邮件
# ! /usr/bin/env python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import sys
import os
import pandas as pd
import datetime
import tkinter.messagebox
import traceback
import xlwings as xw
# 参数:收件人,主题,正文,文件名集合(可发送多个文件),文件路径(文件在同一个路径)
def wain_send_mail(mail_user,mail_pass,sub, content, files, path):
mailto_list = [''] # 收件人列表,以英文逗号分隔
mail_host = "smtp.263.net" # 使用的邮箱的smtp服务器地址,这里是263的smtp地址
# mail_user = "****@qq.com" # 用户名
# mail_pass = "" # 授权码,不是密码,授权码要在邮箱设置中获取
Cc_list = ['抄送人员列表']
me = "<" + mail_user + ">"
msg = MIMEMultipart()
msg.attach(MIMEText(content, _subtype='html', _charset='utf-8'))
msg['Subject'] = sub
msg['From'] = me
msg['To'] = ",".join(mailto_list) # 将收件人列表以‘,’分隔
msg['Cc'] = ",".join(Cc_list) # 将收件人列表以‘,’分隔
for file in files:
if os.path.isfile(path + '/' + file):
# 构造附件
att = MIMEText(open(path + '/' + file, 'rb').read(), 'base64', 'utf-8')
att["Content-Type"] = 'application/octet-stream'
att.add_header("Content-Disposition", "attachment", filename=("gbk", "", file))
msg.attach(att)
try:
server = smtplib.SMTP()
if mail_host == 'smtp.gmail.com':
server.connect(mail_host, port=587) # 连接服务器
server.starttls()
else:
server.connect(mail_host)
server.login(mail_user, mail_pass) # 登录操作
server.sendmail(me, mailto_list + Cc_list, msg.as_string())
server.close()
print('Mail sent successfully')
shijian = '已发送,' + str(datetime.datetime.now())
return shijian
except Exception as e:
print('Mail sent failed')
print(sys.exc_info()[0], sys.exc_info()[1])
shijian = '1,发送失败'
return shijian