小白一枚,欢迎大神指点
需求:
写一个python脚本,获取所有未读邮件并将邮件信息打入钉钉群中
增加钉钉文本长度限制处理:电脑客户端和手机客户端发DING,最多可以发送5000以内的字符
新邮件内容文件位置:email_content/年月日/用户/tiamstamp.txt
执行脚本日志文件位置:email_log/用户/年月日.log
附件下载开关:attach_status=True/Fales
附件下载位置(与新邮件内容文件同级目录):email_content/年月日/用户/***
附件命名方式:主题+附件后缀
# -*- coding: utf-8 -*-
"""
function: IMAP收取邮件
date: 2021-11-10
"""
import email
import email.header
import imaplib
import json
import requests
import os
import datetime, time
class IMAP:
def __init__(self):
## 是否下载附件开关 False/True
self.attach_status = True
self.user_id = '邮箱账号'
self.password = '邮箱密码'
self.imap_server = 'map.exmail.qq.com'
self.DD_Webhook = '钉钉接口'
self.current_date = datetime.datetime.now().strftime("%Y%m%d")
self.email_path = 'email_content/{}/{}/'.format(self.current_date,self.user_id)
self.email_log_path = 'email_log/'
self.check()
self.get_content(self.login())
self.loginout(self.login())
def check(self):
if not os.path.exists(self.email_path):
os.makedirs(self.email_path)
if not os.path.exists(self.email_log_path):
os.makedirs(self.email_log_path)
def login(self):
try:
serv = imaplib.IMAP4_SSL(self.imap_server, 993)
print('邮箱服务器连接成功')
except Exception as e:
print('邮箱服务器连接失败:', e)
with open('{}{}.log'.format(self.email_log_path, self.current_date), 'a', encoding='utf-8') as f:
f.write("[失败]:{}\t{}\t邮箱服务器连接失败\n\n\n".format(time.asctime(time.localtime(time.time())),self.user_id))
f.close()
exit(1)
try:
serv.login(self.user_id, self.password)
print('账号登录成功')
return serv
except Exception as e:
print('账号登录失败:', e)
with open('{}{}.log'.format(self.email_log_path, self.current_date), 'a', encoding='utf-8') as f:
f.write("[失败]:{}\t{}\t账号登录失败\n".format(time.asctime(time.localtime(time.time())),self.user_id))
f.close()
exit(1)
def loginout(self, conn):
"""
登出邮件服务器
:param conn: imap连接
:return:
"""
conn.close
conn.logout()
print('退出账号登录')
def get_content(self, conn):
"""
获取指定邮件,解析内容
:param conn: imap连接
:return:
"""
# 在连接服务器后,搜索之前,需要选择邮箱,默认select(mailbox='INBOX', readonly=False)
conn.select()
# 筛选符合条件的邮件,这里不知道怎么过滤复杂条件,只能过滤未读邮件或全部
ret, data = conn.search(None, 'UNSEEN') # 未读邮件
# 邮件列表
email_list = data[0].split()
if len(email_list) == 0:
print('收件箱为空,程序退出')
with open('{}{}.log'.format(self.email_log_path, self.current_date), 'a', encoding='utf-8') as f:
f.write("[成功]:{}\t{}\t收件箱为空\n".format(time.asctime(time.localtime(time.time())),self.user_id))
f.close()
exit(1)
# 获取邮件的序号
for i in range(len(email_list)):
# 获取邮件内容
item = email_list[i]
ret, data = conn.fetch(item, '(RFC822)')
msg = email.message_from_string(data[0][1].decode('UTF-8'))
sub = msg.get('subject')
email_from = msg.get('from')
email_to = msg.get('to')
email_Cc = msg.get('Cc')
email_date = msg.get('Date')[:24]
sub_text = email.header.decode_header(sub)
email_from_text = email.header.decode_header(email_from)
email_to_text = email.header.decode_header(email_to)
email_date_text = email.header.decode_header(email_date)
try:
email_Cc_text = email.header.decode_header(email_Cc)
except Exception as e:
pass
if sub_text[0]:
sub_detail = self.tuple_to_str(sub_text[0])
email_from_detail = ''
for i in range(len(email_from_text)):
email_from_detail = email_from_detail + self.tuple_to_str(email_from_text[i])
email_to_detail = ''
for i in range(len(email_to_text)):
email_to_detail = email_to_detail + self.tuple_to_str(email_to_text[i])
for i in range(len(email_date_text)):
email_date_detail = self.tuple_to_str(email_date_text[i])
email_Cc_detail = ''
try:
for i in range(len(email_Cc_text)):
email_Cc_detail = email_Cc_detail + self.tuple_to_str(email_Cc_text[i])
except Exception as e:
pass
print('主题:', sub_detail)
print('时间:', email_date_detail)
# print('发件人:', email_from_detail)
# print('收件人:', email_to_detail)
# print('抄送人:', email_Cc_detail)
# 通过walk可以遍历出所有的内容
file_name = '无'
cc = ''
for part in msg.walk():
# 这里要判断是否是multipart,如果是,数据没用丢弃
if not part.is_multipart():
# 字符集
# charset = part.get_charset()
# print('charset: ', charset)
# 内容类型
content_type = part.get_content_type()
# print('content-type', content_type)
# 如果是附件,这里就会取出附件的文件名,以下两种方式都可以获取
# name = part.get_param("name")
name = part.get_filename()
if self.attach_status:
if name:
# 附件
# 中文名获取到的是=?GBK?Q?=D6=D0=CE=C4=C3=FB.docx?=(中文名.docx)格式,需要将其解码为bytes格式
trans_name = email.header.decode_header(name)
if trans_name[0][1]:
# 将bytes格式转为可读格式
file_name = trans_name[0][0].decode(trans_name[0][1])
else:
file_name = trans_name[0][0]
print('开始下载附件:', file_name)
attach_data = part.get_payload(decode=True) # 解码出附件数据,然后存储到文件中
try:
f = open(
'{}{}.{}'.format(self.email_path, sub_detail, file_name.rsplit('.', maxsplit=1)[1]),
'wb') # 注意一定要用wb来打开文件,因为附件一般都是二进制文件
except Exception as e:
print(e)
f = open('tmp', 'wb')
f.write(attach_data)
f.close()
print('附件下载成功:', file_name)
txt = part.get_payload(decode=True) # 解码文本内容
if content_type == 'text/plain':
try:
cc = str(txt, 'GBK').replace(' ', ' ').replace('&', '&').replace('<',
'<').replace(
'>', '>').replace('"', '"').replace('&qpos;', "'")
except:
cc = str(txt, 'UTF-8').replace(' ', ' ').replace('&', '&').replace('<',
'<').replace(
'>', '>').replace('"', '"').replace('&qpos;', "'")
DD_limit = 4000
sign = 0
for num in range((int(len(cc)) // DD_limit) + 1):
text = cc[sign:DD_limit]
sign += 4000
DD_limit += 4000
print(text)
msg1 = """主题: {}
时间: {}
发件人: {}
收件人: {}
抄送人: {}
附件: {}
邮件内容如下:
{}""".format(sub_detail, email_date_detail, email_from_detail, email_to_detail, email_Cc_detail, file_name, text)
HEADERS = {"Content-Type": "application/json;charset=utf-8"}
url = self.DD_Webhook
data_info = {
"msgtype": "text",
"text": {
"content": msg1
},
"isAtAll": True
}
# 转化成自己需要的数据格式:转换成python格式的数据
# value = bytes(json.dumps(data_info,ensure_ascii=False,indent=4),"utf-8")
value = json.dumps(data_info)
response = requests.post(url, data=value, headers=HEADERS)
conn.store(item, '+FLAGS', r'(\Seen)')
with open('{}tiamstamp.txt'.format(self.email_path), 'a', encoding='utf-8') as f:
f.write("%s \n\n\n" % msg1)
f.close()
with open('{}{}.log'.format(self.email_log_path, self.current_date), 'a', encoding='utf-8') as f:
f.write("[成功]:{}\t{}\t主题:{}\t附件:{}\n".format(time.asctime(time.localtime(time.time())), self.user_id,sub_detail,
file_name))
f.close()
def tuple_to_str(self, tuple_):
"""
元组转为字符串输出
:param tuple_: 转换前的元组,QQ邮箱格式为(b'\xcd\xf5\xd4\xc6', 'gbk')或者(b' <XXXX@163.com>', None),163邮箱格式为('<XXXX@163.com>', None)
:return: 转换后的字符串
"""
if tuple_[1]:
out_str = tuple_[0].decode(tuple_[1])
else:
if isinstance(tuple_[0], bytes):
out_str = tuple_[0].decode('UTF-8')
else:
out_str = tuple_[0]
return out_str
if __name__ == '__main__':
IMAP()
执行结果如下: