
1 import imaplib
2 import email
3 import re
4 import time
5 from email.header import decode_header, Header
6 from datetime import datetime, timedelta
7 from email.utils import parseaddr
8 import util
9 from config import FILE_PATH_PREFIX, FILE_DOMAIN_PREFIX, FILE_PATH_PREFIX_ALIAS
10 import os
11
12 imaplib.Commands['ID'] = ('AUTH')
13
14
15 def decode_data(content, added_encode=None):
16 """解码"""
17
18 def _decode(bytes_, msg_charset):
19 try:
20 if isinstance(bytes_, bytes):
21 return str(bytes_, encoding=msg_charset)
22 else:
23 return str(bytes_).split(' ')[0]
24 except Exception as e:
25 return None
26
27 encodes = ['UTF-8', 'GBK', 'GB2312']
28 if added_encode:
29 encodes = [added_encode] + encodes
30 for encoding in encodes:
31 if r'\u' in str(content):
32 str_data = _decode(content, 'unicode-escape')
33 else:
34 str_data = _decode(content, encoding)
35 if str_data is not None:
36 return str_data
37 return None
38
39
40 def get_local_time_stamp(msg, date):
41 """将邮箱时间转换为北京时间"""
42 if date is None:
43 if msg['Received']:
44 date = msg['Received'].split(';')[-1].strip()
45 else:
46 return None
47 if ',' not in date:
48 date = msg['Received'].split(';')[-1].strip()
49 result = re.search(r"[\-+]\d+", date)
50 if result:
51 time_area = result.group()
52 symbol = time_area[0]
53 offset = int(time_area[1]) + int(time_area[2])
54 date_re = re.compile(r'[(](.*?)[)]', re.S)
55 time_zone = re.findall(date_re, date)
56 if time_zone:
57 format_str = '%a, %d %b %Y %H:%M:%S ' + time_area + ' ({})'.format(time_zone[0])
58 else:
59 format_str = '%a, %d %b %Y %H:%M:%S ' + time_area
60 if symbol == "+":
61 utc_time = time.strptime(date.strip(), format_str)
62 temps_time = datetime.fromtimestamp(time.mktime(utc_time))
63 if offset > 8:
64 offset = offset - 8
65 elif offset < 8:
66 offset = 8 - offset
67 else:
68 offset = 0
69 local_temps_time = temps_time + timedelta(hours=offset)
70 else:
71 utc_time = time.strptime(date.strip(), format_str)
72 temps_time = datetime.fromtimestamp(time.mktime(utc_time))
73 local_temps_time = temps_time + timedelta(hours=(offset + 8))
74 return local_temps_time
75 else:
76 time_zone = date[-3:]
77 format_str = '%a, %d %b %Y %H:%M:%S {}'.format(time_zone)
78 utc_time = time.strptime(date.strip(), format_str)
79 temps_time = datetime.fromtimestamp(time.mktime(utc_time))
80 if time_zone == 'UTC' or time_zone == 'GMT':
81 hours_ = 8
82 elif time_zone == 'CDT':
83 hours_ = 13
84 else:
85 hours_ = 0
86 local_temps_time = temps_time + timedelta(hours=hours_)
87 return local_temps_time
88
89
90 def parse_email_body(message):
91 """解析内容"""
92 content_list = []
93 for part in message.walk():
94 if not part.is_multipart():
95 charset = part.get_charset()
96 contentType = part.get_content_type()
97 if contentType == 'text/plain' or contentType == 'text/html':
98 mail_content = decode_data(part.get_payload(decode=True), charset)
99 content_list.append(mail_content)
100 for i in content_list:
101 if 'html' in i:
102 content = i
103 return content
104 return content_list[0]
105
106
107 def parse_email_annex(message, client_id, from_email, send_email, mail_subject, mail_content, email_time):
108 """ 解析保存附件 """
109 annex_list = []
110 for part in message.walk():
111 # 获取附件名称类型
112 file_name = part.get_filename()
113 if not part.is_multipart():
114 if file_name:
115 # 附件内容,先检测是否已存有该附件再保存
116 file_name = decode_header(Header(file_name))
117 annex_name = file_name[0][0]
118 if file_name[0][1]:
119 value, charset = decode_header(str(annex_name, file_name[0][1]))[0]
120 annex_name = decode_data(value, charset)
121 pwd = util.file_path(FILE_PATH_PREFIX + 'annex/')
122 id_ = str(int(time.time()))
123 url_ = FILE_DOMAIN_PREFIX + FILE_PATH_PREFIX_ALIAS + 'annex/' + pwd.split('/')[-2] + '/' + id_ + '_' \
124 + annex_name
125 path_ = pwd + id_ + '_' + annex_name
126 if not os.path.isfile(path_):
127 fp = open(path_, 'wb')
128 fp.write(part.get_payload(decode=True))
129 fp.close()
130 annex_list.append({'annexName': annex_name, 'annexUrl': url_, 'annexPath': path_})
131 return annex_list
132
133
134 def get_email(server, username, password, send_email, client_id, created_by):
135 """
136 获取邮件信息并保存
137 https://www.docs4dev.com/docs/zh/python/3.7.2rc1/all/library-imaplib.html
138 """
139 # if first_run:
140 # mail_status = 'All'
141 # mail_num = -30
142 # else:
143 # mail_status = 'UnSeen'
144 # mail_num = -10
145 try:
146 imap = imaplib.IMAP4_SSL(server)
147 try:
148 imap.login(username, password)
149 except Exception as e:
150 print('账号:{} 登录失败:{}'.format(username, e))
151 else:
152 # 通过遍历查看imap中有哪些mailbox的值可以选择:
153 # for i in imap.list()[1]:
154 # print('i:', i)
155 # mailbox:INBOX(默认收件箱)/Drafts(草稿箱)/Junk(垃圾箱)/Trash(已删除)/Sent(已发送)
156 mail_box = ['INBOX']
157 # 针对网易邮箱被阻止:https://blog.csdn.net/jony_online/article/details/108638571
158 args = ("name", username, "contact", username, "version", "1.0.0", "vendor", "myclient")
159 imap._simple_command('ID', '("' + '" "'.join(args) + '")')
160 for i in mail_box:
161 try:
162 imap.select(mailbox=i)
163 typ, data = imap.search(None, 'All') # UnSeen 未读邮件
164 except:
165 imap.select()
166 typ, data = imap.search(None, 'All')
167 for num in data[0].split()[-10:]:
168 typ, data = imap.fetch(num, '(RFC822)')
169 str_message = decode_data(data[0][1])
170 message = email.message_from_string(str_message)
171 sub = message.get('subject')
172 if sub:
173 mail_subject = ''
174 msgCharset = ''
175 for i in range(len(decode_header(sub))):
176 subject_, charset = decode_header(sub)[i]
177 msgCharset = charset
178 if charset is not None:
179 # subject_ = subject_.decode(charset)
180 subject_ = decode_data(subject_, charset)
181 mail_subject += subject_
182 else:
183 subject_ = decode_data(subject_, charset)
184 mail_subject += subject_
185 # print('mail_subject:', mail_subject)
186 from_email = parseaddr(message.get('from'))[1] # 发件人邮箱
187 from_name = message.get('from').split('<')[0].strip()
188 if '"' in from_name:
189 from_name = from_name.strip('"')
190 from_name = decode_data(decode_header(from_name)[0][0], msgCharset) # 发件人名称
191 # to_email = parseaddr(message.get('to'))[1] # 收件人邮箱
192 date_ = get_local_time_stamp(message, message.get('date'))
193 if date_ is not None:
194 email_time = date_.timestamp() # 收件时间
195 else:
196 email_time = time.time()
197 mail_content = parse_email_body(message)
198 # 将获取到的客户端上的邮件改为已读状态
199 # imap.store(num, '+FLAGS', '(\\Seen)')
200 imap.close()
201 imap.logout()
202 except:
203 pass