ezKit 1.7.1__py3-none-any.whl → 1.7.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ezKit/sendemail.py +186 -64
- {ezKit-1.7.1.dist-info → ezKit-1.7.3.dist-info}/METADATA +2 -3
- {ezKit-1.7.1.dist-info → ezKit-1.7.3.dist-info}/RECORD +6 -6
- {ezKit-1.7.1.dist-info → ezKit-1.7.3.dist-info}/WHEEL +1 -1
- {ezKit-1.7.1.dist-info → ezKit-1.7.3.dist-info}/LICENSE +0 -0
- {ezKit-1.7.1.dist-info → ezKit-1.7.3.dist-info}/top_level.txt +0 -0
ezKit/sendemail.py
CHANGED
@@ -1,29 +1,62 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
"""
|
2
|
+
发送邮件
|
3
|
+
"""
|
4
|
+
# https://stackoverflow.com/questions/882712/sending-html-email-using-python
|
5
|
+
# pylint: disable=E0611
|
6
|
+
# pylint: disable=R0911
|
7
|
+
# pylint: disable=R0912
|
8
|
+
# pylint: disable=R0913
|
9
|
+
# pylint: disable=R0914
|
10
|
+
# pylint: disable=R0915
|
11
|
+
# pylint: disable=R1710
|
4
12
|
import smtplib
|
5
13
|
from email.header import Header
|
6
14
|
from email.mime.image import MIMEImage
|
7
15
|
from email.mime.multipart import MIMEMultipart
|
8
16
|
from email.mime.text import MIMEText
|
9
17
|
from email.utils import formataddr, parseaddr
|
18
|
+
from typing import Optional, TypedDict, cast
|
10
19
|
|
11
20
|
from loguru import logger
|
12
21
|
|
13
22
|
from . import utils
|
14
23
|
|
15
24
|
|
25
|
+
class TypedSMTP(TypedDict):
|
26
|
+
"""smtp type"""
|
27
|
+
server: str
|
28
|
+
port: int
|
29
|
+
tls: bool
|
30
|
+
|
31
|
+
class TypedSender(TypedDict):
|
32
|
+
"""sender type"""
|
33
|
+
name: str
|
34
|
+
address: str
|
35
|
+
password: str
|
36
|
+
|
37
|
+
class TypedBody(TypedDict, total=False):
|
38
|
+
"""body type"""
|
39
|
+
content: str
|
40
|
+
type: Optional[str]
|
41
|
+
|
16
42
|
def format_parse(s):
|
17
43
|
_name, _addr = parseaddr(s)
|
18
|
-
return formataddr((Header(_name,
|
19
|
-
|
20
|
-
def
|
21
|
-
|
44
|
+
return formataddr((Header(_name, "utf-8").encode(), _addr))
|
45
|
+
|
46
|
+
def sendemail(
|
47
|
+
smtp: TypedSMTP,
|
48
|
+
sender: TypedSender,
|
49
|
+
recipients: str | list,
|
50
|
+
subject: str,
|
51
|
+
body: TypedBody,
|
52
|
+
images: None | list = None
|
53
|
+
) -> bool:
|
54
|
+
"""
|
22
55
|
smtp SMTP信息
|
23
56
|
|
24
|
-
server
|
25
|
-
port
|
26
|
-
|
57
|
+
server SMTP地址
|
58
|
+
port SMTP端口
|
59
|
+
tls 是否使用TLS
|
27
60
|
|
28
61
|
sender 发件人信息
|
29
62
|
|
@@ -31,15 +64,20 @@ def related_html(smtp=None, sender=None, recipients=None, subject=None, html_fil
|
|
31
64
|
address 发件人邮箱地址
|
32
65
|
password 发件人邮箱密码(SMTP)
|
33
66
|
|
34
|
-
recipients
|
35
|
-
|
36
|
-
|
67
|
+
recipients 收件人(或列表)
|
68
|
+
|
69
|
+
subject 邮件主题
|
70
|
+
|
71
|
+
body 邮件主体
|
72
|
+
|
73
|
+
content 内容
|
74
|
+
type 类型 (默认 plain, 或者 file, 或者 html)
|
37
75
|
|
38
76
|
images 图片列表(可选)
|
39
77
|
|
40
78
|
cid 图片CID
|
41
79
|
path 图片路径
|
42
|
-
|
80
|
+
"""
|
43
81
|
|
44
82
|
# 参数判断
|
45
83
|
# match True:
|
@@ -59,88 +97,172 @@ def related_html(smtp=None, sender=None, recipients=None, subject=None, html_fil
|
|
59
97
|
# logger.error('ERROR!! {} is not string or none'.format('html_file'))
|
60
98
|
# return False
|
61
99
|
|
62
|
-
logger.success(
|
100
|
+
logger.success("sendemail start")
|
63
101
|
|
64
102
|
try:
|
65
103
|
|
66
|
-
|
104
|
+
# 邮件主体
|
105
|
+
|
106
|
+
if utils.v_true(body, dict) is False:
|
107
|
+
logger.error("body error")
|
108
|
+
return False
|
67
109
|
|
68
|
-
|
110
|
+
message: MIMEMultipart = MIMEMultipart()
|
69
111
|
|
70
|
-
|
112
|
+
body_content = cast(str, body.get("content"))
|
71
113
|
|
72
|
-
|
114
|
+
if utils.v_true(body_content, str) is False:
|
115
|
+
logger.error(f"body content error: {body_content}")
|
116
|
+
return False
|
73
117
|
|
74
|
-
|
118
|
+
body_type = cast(str, body.get("type"))
|
75
119
|
|
76
|
-
|
120
|
+
# 从文本文件读取内容
|
121
|
+
if body_type == "file":
|
122
|
+
with open(body_content, "r", encoding="utf-8") as file:
|
123
|
+
message.attach(MIMEText(file.read(), "plain", "utf-8"))
|
77
124
|
|
78
|
-
|
125
|
+
# 从HTML文件读取内容
|
126
|
+
elif body_type == "html":
|
127
|
+
message = MIMEMultipart("related")
|
128
|
+
with open(body_content, "r", encoding="utf-8") as file:
|
129
|
+
message.attach(MIMEText(file.read(), "html", "utf-8"))
|
79
130
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
mime_image = MIMEImage(image_file.read())
|
84
|
-
# Define the image's ID as referenced above
|
85
|
-
mime_image.add_header('Content-ID', '<CID>')
|
86
|
-
message.attach(mime_image)
|
87
|
-
'''
|
131
|
+
# 纯文本内容
|
132
|
+
else:
|
133
|
+
message.attach(MIMEText(body_content, "plain", "utf-8"))
|
88
134
|
|
89
|
-
|
90
|
-
_mime_image = MIMEImage(_image_file.read())
|
91
|
-
_mime_image.add_header('Content-ID', '<{}>'.format(_image['cid']))
|
92
|
-
_message.attach(_mime_image)
|
135
|
+
# ------------------------------------------------------------------------------------------
|
93
136
|
|
94
|
-
|
137
|
+
# SMTP
|
95
138
|
|
96
|
-
|
139
|
+
if utils.v_true(smtp, dict) is False:
|
140
|
+
logger.error("smtp error")
|
141
|
+
return False
|
97
142
|
|
98
|
-
|
99
|
-
|
100
|
-
|
143
|
+
smtp_host = cast(str, smtp.get("server"))
|
144
|
+
smtp_port = cast(int, smtp.get("port"))
|
145
|
+
smtp_tls = cast(bool, smtp.get("tls"))
|
101
146
|
|
102
|
-
|
103
|
-
|
147
|
+
if utils.v_true(smtp_host, str) is False:
|
148
|
+
logger.error(f"smtp host error: {smtp_host}")
|
149
|
+
return False
|
150
|
+
|
151
|
+
if utils.v_true(smtp_port, int) is False:
|
152
|
+
logger.error(f"smtp port error: {smtp_port}")
|
153
|
+
return False
|
154
|
+
|
155
|
+
smtp_tls = utils.v_true(smtp_tls, bool)
|
156
|
+
|
157
|
+
# ------------------------------------------------------------------------------------------
|
158
|
+
|
159
|
+
# 发件人信息
|
160
|
+
|
161
|
+
if utils.v_true(sender, dict) is False:
|
162
|
+
logger.error("sender error")
|
163
|
+
return False
|
164
|
+
|
165
|
+
sender_name = cast(str, sender.get("name"))
|
166
|
+
sender_address = cast(str, sender.get("address"))
|
167
|
+
sender_password = cast(str, sender.get("password"))
|
168
|
+
|
169
|
+
if utils.v_true(sender_name, str) is False:
|
170
|
+
logger.error(f"sender name error: {sender_name}")
|
171
|
+
return False
|
172
|
+
|
173
|
+
if utils.v_true(sender_address, str) is False:
|
174
|
+
logger.error(f"sender address error: {sender_address}")
|
175
|
+
return False
|
176
|
+
|
177
|
+
if utils.v_true(sender_password, str) is False:
|
178
|
+
logger.error(f"sender password error: {sender_password}")
|
179
|
+
return False
|
180
|
+
|
181
|
+
message["From"] = formataddr((sender_name, sender_address))
|
182
|
+
|
183
|
+
# ------------------------------------------------------------------------------------------
|
184
|
+
|
185
|
+
# 收件人(或列表)
|
104
186
|
|
105
|
-
# 收件人
|
106
187
|
if utils.v_true(recipients, str):
|
107
|
-
|
188
|
+
message["To"] = format_parse(recipients)
|
108
189
|
elif utils.v_true(recipients, list):
|
109
|
-
|
190
|
+
message["To"] = ", ".join(list(map(format_parse, recipients)))
|
110
191
|
else:
|
111
|
-
logger.error(
|
192
|
+
logger.error("recipients error")
|
112
193
|
return False
|
113
194
|
|
114
|
-
#
|
115
|
-
_message['Subject'] = subject
|
195
|
+
# ------------------------------------------------------------------------------------------
|
116
196
|
|
117
|
-
|
118
|
-
发送邮件
|
197
|
+
# 邮件主题
|
119
198
|
|
120
|
-
|
199
|
+
if utils.v_true(subject, str) is False:
|
200
|
+
logger.error("subject error")
|
201
|
+
return False
|
121
202
|
|
122
|
-
|
123
|
-
https://docs.python.org/3/library/smtplib.html#smtplib.SMTP.sendmail
|
124
|
-
https://gist.github.com/AO8/c5a6f747eeeca02351152ae8dc79b537
|
125
|
-
'''
|
203
|
+
message["Subject"] = subject
|
126
204
|
|
127
|
-
|
205
|
+
# ------------------------------------------------------------------------------------------
|
128
206
|
|
129
|
-
|
130
|
-
_smtp.login(sender.get('address'), sender.get('password'))
|
131
|
-
_smtp.sendmail(sender.get('address'), recipients, _message.as_string())
|
207
|
+
if images is not None and utils.v_true(images, list):
|
132
208
|
|
133
|
-
|
209
|
+
for image in images:
|
210
|
+
|
211
|
+
try:
|
212
|
+
|
213
|
+
if utils.check_file_type(image.get("path", ""), "file"):
|
134
214
|
|
135
|
-
|
136
|
-
|
137
|
-
|
215
|
+
# 添加图片
|
216
|
+
# with open(image_path, "rb") as image_file:
|
217
|
+
# mime_image = MIMEImage(image_file.read())
|
218
|
+
# # Define the image's ID as referenced above
|
219
|
+
# mime_image.add_header("Content-ID", "<CID>")
|
220
|
+
# message.attach(mime_image)
|
138
221
|
|
139
|
-
|
222
|
+
with open(image["path"], "rb") as _image_file:
|
223
|
+
mime_image = MIMEImage(_image_file.read())
|
224
|
+
mime_image.add_header("Content-ID", f"<{image['cid']}>")
|
225
|
+
message.attach(mime_image)
|
140
226
|
|
141
|
-
|
227
|
+
except Exception as e:
|
228
|
+
logger.exception(e)
|
229
|
+
return False
|
230
|
+
|
231
|
+
# ------------------------------------------------------------------------------------------
|
232
|
+
|
233
|
+
# 发送邮件
|
234
|
+
|
235
|
+
# SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
|
236
|
+
#
|
237
|
+
# to_addrs = sender_to + sender_cc
|
238
|
+
# https://docs.python.org/3/library/smtplib.html#smtplib.SMTP.sendmail
|
239
|
+
# https://gist.github.com/AO8/c5a6f747eeeca02351152ae8dc79b537
|
240
|
+
|
241
|
+
# if smtp.get('ssl', False) is True:
|
242
|
+
|
243
|
+
# with smtplib.SMTP_SSL(smtp_host, smtp_port) as _smtp:
|
244
|
+
# _smtp.login(sender_address, sender_password)
|
245
|
+
# _smtp.sendmail(sender_address, recipients, _message.as_string())
|
246
|
+
|
247
|
+
# else:
|
248
|
+
|
249
|
+
with smtplib.SMTP(smtp_host, smtp_port) as smtp_server:
|
250
|
+
if smtp_tls is True:
|
251
|
+
smtp_server.starttls()
|
252
|
+
smtp_server.login(sender_address, sender_password)
|
253
|
+
smtp_server.sendmail(sender_address, recipients, message.as_string())
|
254
|
+
|
255
|
+
logger.success("sendemail success")
|
256
|
+
|
257
|
+
return True
|
142
258
|
|
143
259
|
except Exception as e:
|
260
|
+
|
261
|
+
# 忽略腾讯邮箱返回的异常
|
262
|
+
if e.args == (-1, b'\x00\x00\x00'):
|
263
|
+
# pass
|
264
|
+
return True
|
265
|
+
|
144
266
|
logger.error('sendemail error')
|
145
267
|
logger.exception(e)
|
146
268
|
return False
|
@@ -10,13 +10,13 @@ ezKit/plots.py,sha256=QUtoVfZ49ZSNcY8gcQ2TYVkMjDDzoW-myMtqTi5WN2U,5322
|
|
10
10
|
ezKit/qywx.py,sha256=7eWrlTLrUj6U6cViEGbT6_LQxFGVqkhGAefBSS6T_-0,6531
|
11
11
|
ezKit/redis.py,sha256=pY4SPlcgQ7S8IeY2xoDpxy-xCZxzZQrQJNAoWRsC1dI,1773
|
12
12
|
ezKit/reports.py,sha256=dBBggggCCLuk5YD6SjdUPuxTr3wiJojP3lA7dQfg6Pk,8898
|
13
|
-
ezKit/sendemail.py,sha256=
|
13
|
+
ezKit/sendemail.py,sha256=AAdxBvEYN_AJVvBkSAvXzhXC5jkbRsD_8P51h2SdTRw,8413
|
14
14
|
ezKit/token.py,sha256=4L6A26KsxvB4WfF8R7SYiBmihJK0PiN5Oh7dgDVJtxU,1382
|
15
15
|
ezKit/utils.py,sha256=VkZzKy_jupr25Axa5I0juMsm1XiaimyiPoSITA91jcg,47826
|
16
16
|
ezKit/xftp.py,sha256=qbCqFcGe22TDBSisj0Zoz78tnydDWoOfvywWpXdfaGw,6982
|
17
17
|
ezKit/zabbix.py,sha256=soM5UEeYMfm7NczbPOVLirmHm3G20dECQ0aCBttZfhQ,28350
|
18
|
-
ezKit-1.7.
|
19
|
-
ezKit-1.7.
|
20
|
-
ezKit-1.7.
|
21
|
-
ezKit-1.7.
|
22
|
-
ezKit-1.7.
|
18
|
+
ezKit-1.7.3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
19
|
+
ezKit-1.7.3.dist-info/METADATA,sha256=KisYwblMheFnzhCtB9WvgESi3-Z8VsnZ8jJPrw1swGQ,163
|
20
|
+
ezKit-1.7.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
21
|
+
ezKit-1.7.3.dist-info/top_level.txt,sha256=aYLB_1WODsqNTsTFWcKP-BN0KCTKcV-HZJ4zlHkCFw8,6
|
22
|
+
ezKit-1.7.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|