ezKit 1.7.1__tar.gz → 1.7.3__tar.gz
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-1.7.1/ezKit.egg-info → ezkit-1.7.3}/PKG-INFO +2 -2
- ezkit-1.7.3/ezKit/sendemail.py +268 -0
- {ezkit-1.7.1 → ezkit-1.7.3/ezKit.egg-info}/PKG-INFO +2 -2
- {ezkit-1.7.1 → ezkit-1.7.3}/setup.py +2 -2
- ezkit-1.7.1/ezKit/sendemail.py +0 -146
- {ezkit-1.7.1 → ezkit-1.7.3}/LICENSE +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/MANIFEST.in +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/README.md +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/__init__.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/bottle.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/bottle_extensions.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/cipher.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/database.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/files.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/http.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/mongo.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/plots.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/qywx.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/redis.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/reports.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/token.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/utils.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/xftp.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit/zabbix.py +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit.egg-info/SOURCES.txt +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit.egg-info/dependency_links.txt +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/ezKit.egg-info/top_level.txt +0 -0
- {ezkit-1.7.1 → ezkit-1.7.3}/setup.cfg +0 -0
@@ -0,0 +1,268 @@
|
|
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
|
12
|
+
import smtplib
|
13
|
+
from email.header import Header
|
14
|
+
from email.mime.image import MIMEImage
|
15
|
+
from email.mime.multipart import MIMEMultipart
|
16
|
+
from email.mime.text import MIMEText
|
17
|
+
from email.utils import formataddr, parseaddr
|
18
|
+
from typing import Optional, TypedDict, cast
|
19
|
+
|
20
|
+
from loguru import logger
|
21
|
+
|
22
|
+
from . import utils
|
23
|
+
|
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
|
+
|
42
|
+
def format_parse(s):
|
43
|
+
_name, _addr = parseaddr(s)
|
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
|
+
"""
|
55
|
+
smtp SMTP信息
|
56
|
+
|
57
|
+
server SMTP地址
|
58
|
+
port SMTP端口
|
59
|
+
tls 是否使用TLS
|
60
|
+
|
61
|
+
sender 发件人信息
|
62
|
+
|
63
|
+
name 发件人名称
|
64
|
+
address 发件人邮箱地址
|
65
|
+
password 发件人邮箱密码(SMTP)
|
66
|
+
|
67
|
+
recipients 收件人(或列表)
|
68
|
+
|
69
|
+
subject 邮件主题
|
70
|
+
|
71
|
+
body 邮件主体
|
72
|
+
|
73
|
+
content 内容
|
74
|
+
type 类型 (默认 plain, 或者 file, 或者 html)
|
75
|
+
|
76
|
+
images 图片列表(可选)
|
77
|
+
|
78
|
+
cid 图片CID
|
79
|
+
path 图片路径
|
80
|
+
"""
|
81
|
+
|
82
|
+
# 参数判断
|
83
|
+
# match True:
|
84
|
+
# case True if utils.vTrue(smtp, dict) == False:
|
85
|
+
# logger.error('ERROR!! {} is not dictionary or none'.format('smtp'))
|
86
|
+
# return False
|
87
|
+
# case True if utils.vTrue(sender, dict) == False:
|
88
|
+
# logger.error('ERROR!! {} is not dictionary or none'.format('sender'))
|
89
|
+
# return False
|
90
|
+
# case True if (utils.vTrue(recipients, str) == False) and (utils.vTrue(recipients, list) == False):
|
91
|
+
# logger.error('ERROR!! {} is not list or none'.format('recipients'))
|
92
|
+
# return False
|
93
|
+
# case True if utils.vTrue(subject, str) == False:
|
94
|
+
# logger.error('ERROR!! {} is not string or none'.format('subject'))
|
95
|
+
# return False
|
96
|
+
# case True if utils.vTrue(html_file, str) == False:
|
97
|
+
# logger.error('ERROR!! {} is not string or none'.format('html_file'))
|
98
|
+
# return False
|
99
|
+
|
100
|
+
logger.success("sendemail start")
|
101
|
+
|
102
|
+
try:
|
103
|
+
|
104
|
+
# 邮件主体
|
105
|
+
|
106
|
+
if utils.v_true(body, dict) is False:
|
107
|
+
logger.error("body error")
|
108
|
+
return False
|
109
|
+
|
110
|
+
message: MIMEMultipart = MIMEMultipart()
|
111
|
+
|
112
|
+
body_content = cast(str, body.get("content"))
|
113
|
+
|
114
|
+
if utils.v_true(body_content, str) is False:
|
115
|
+
logger.error(f"body content error: {body_content}")
|
116
|
+
return False
|
117
|
+
|
118
|
+
body_type = cast(str, body.get("type"))
|
119
|
+
|
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"))
|
124
|
+
|
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"))
|
130
|
+
|
131
|
+
# 纯文本内容
|
132
|
+
else:
|
133
|
+
message.attach(MIMEText(body_content, "plain", "utf-8"))
|
134
|
+
|
135
|
+
# ------------------------------------------------------------------------------------------
|
136
|
+
|
137
|
+
# SMTP
|
138
|
+
|
139
|
+
if utils.v_true(smtp, dict) is False:
|
140
|
+
logger.error("smtp error")
|
141
|
+
return False
|
142
|
+
|
143
|
+
smtp_host = cast(str, smtp.get("server"))
|
144
|
+
smtp_port = cast(int, smtp.get("port"))
|
145
|
+
smtp_tls = cast(bool, smtp.get("tls"))
|
146
|
+
|
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
|
+
# 收件人(或列表)
|
186
|
+
|
187
|
+
if utils.v_true(recipients, str):
|
188
|
+
message["To"] = format_parse(recipients)
|
189
|
+
elif utils.v_true(recipients, list):
|
190
|
+
message["To"] = ", ".join(list(map(format_parse, recipients)))
|
191
|
+
else:
|
192
|
+
logger.error("recipients error")
|
193
|
+
return False
|
194
|
+
|
195
|
+
# ------------------------------------------------------------------------------------------
|
196
|
+
|
197
|
+
# 邮件主题
|
198
|
+
|
199
|
+
if utils.v_true(subject, str) is False:
|
200
|
+
logger.error("subject error")
|
201
|
+
return False
|
202
|
+
|
203
|
+
message["Subject"] = subject
|
204
|
+
|
205
|
+
# ------------------------------------------------------------------------------------------
|
206
|
+
|
207
|
+
if images is not None and utils.v_true(images, list):
|
208
|
+
|
209
|
+
for image in images:
|
210
|
+
|
211
|
+
try:
|
212
|
+
|
213
|
+
if utils.check_file_type(image.get("path", ""), "file"):
|
214
|
+
|
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)
|
221
|
+
|
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)
|
226
|
+
|
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
|
258
|
+
|
259
|
+
except Exception as e:
|
260
|
+
|
261
|
+
# 忽略腾讯邮箱返回的异常
|
262
|
+
if e.args == (-1, b'\x00\x00\x00'):
|
263
|
+
# pass
|
264
|
+
return True
|
265
|
+
|
266
|
+
logger.error('sendemail error')
|
267
|
+
logger.exception(e)
|
268
|
+
return False
|
@@ -3,13 +3,13 @@ from setuptools import find_packages, setup
|
|
3
3
|
|
4
4
|
setup(
|
5
5
|
name='ezKit',
|
6
|
-
version='1.7.
|
6
|
+
version='1.7.3',
|
7
7
|
author='septvean',
|
8
8
|
author_email='septvean@gmail.com',
|
9
9
|
description='Easy Kit',
|
10
10
|
packages=find_packages(exclude=['documents', 'tests']),
|
11
11
|
include_package_data=True,
|
12
|
-
python_requires='>=3.
|
12
|
+
python_requires='>=3.10',
|
13
13
|
# install_requires=[
|
14
14
|
# 'loguru>=0.7.0',
|
15
15
|
# 'tomlkit>=0.12.0'
|
ezkit-1.7.1/ezKit/sendemail.py
DELETED
@@ -1,146 +0,0 @@
|
|
1
|
-
'''
|
2
|
-
https://stackoverflow.com/questions/882712/sending-html-email-using-python
|
3
|
-
'''
|
4
|
-
import smtplib
|
5
|
-
from email.header import Header
|
6
|
-
from email.mime.image import MIMEImage
|
7
|
-
from email.mime.multipart import MIMEMultipart
|
8
|
-
from email.mime.text import MIMEText
|
9
|
-
from email.utils import formataddr, parseaddr
|
10
|
-
|
11
|
-
from loguru import logger
|
12
|
-
|
13
|
-
from . import utils
|
14
|
-
|
15
|
-
|
16
|
-
def format_parse(s):
|
17
|
-
_name, _addr = parseaddr(s)
|
18
|
-
return formataddr((Header(_name, 'utf-8').encode(), _addr))
|
19
|
-
|
20
|
-
def related_html(smtp=None, sender=None, recipients=None, subject=None, html_file=None, images=None):
|
21
|
-
'''
|
22
|
-
smtp SMTP信息
|
23
|
-
|
24
|
-
server SMTP地址
|
25
|
-
port SMTP端口
|
26
|
-
ssl 是否使用SSL
|
27
|
-
|
28
|
-
sender 发件人信息
|
29
|
-
|
30
|
-
name 发件人名称
|
31
|
-
address 发件人邮箱地址
|
32
|
-
password 发件人邮箱密码(SMTP)
|
33
|
-
|
34
|
-
recipients 收件人列表
|
35
|
-
subject 邮件主题
|
36
|
-
html_file HTML文件
|
37
|
-
|
38
|
-
images 图片列表(可选)
|
39
|
-
|
40
|
-
cid 图片CID
|
41
|
-
path 图片路径
|
42
|
-
'''
|
43
|
-
|
44
|
-
# 参数判断
|
45
|
-
# match True:
|
46
|
-
# case True if utils.vTrue(smtp, dict) == False:
|
47
|
-
# logger.error('ERROR!! {} is not dictionary or none'.format('smtp'))
|
48
|
-
# return False
|
49
|
-
# case True if utils.vTrue(sender, dict) == False:
|
50
|
-
# logger.error('ERROR!! {} is not dictionary or none'.format('sender'))
|
51
|
-
# return False
|
52
|
-
# case True if (utils.vTrue(recipients, str) == False) and (utils.vTrue(recipients, list) == False):
|
53
|
-
# logger.error('ERROR!! {} is not list or none'.format('recipients'))
|
54
|
-
# return False
|
55
|
-
# case True if utils.vTrue(subject, str) == False:
|
56
|
-
# logger.error('ERROR!! {} is not string or none'.format('subject'))
|
57
|
-
# return False
|
58
|
-
# case True if utils.vTrue(html_file, str) == False:
|
59
|
-
# logger.error('ERROR!! {} is not string or none'.format('html_file'))
|
60
|
-
# return False
|
61
|
-
|
62
|
-
logger.success('sendemail start')
|
63
|
-
|
64
|
-
try:
|
65
|
-
|
66
|
-
_message = MIMEMultipart('related')
|
67
|
-
|
68
|
-
with open(html_file, 'r') as _html_file:
|
69
|
-
|
70
|
-
_message.attach(MIMEText(_html_file.read(), 'html', 'utf-8'))
|
71
|
-
|
72
|
-
if utils.v_true(images, list):
|
73
|
-
|
74
|
-
for _image in images:
|
75
|
-
|
76
|
-
try:
|
77
|
-
|
78
|
-
if utils.check_file_type(_image.get('path', ''), 'file'):
|
79
|
-
|
80
|
-
'''
|
81
|
-
添加图片
|
82
|
-
with open(image_path, 'rb') as image_file:
|
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
|
-
'''
|
88
|
-
|
89
|
-
with open(_image['path'], 'rb') as _image_file:
|
90
|
-
_mime_image = MIMEImage(_image_file.read())
|
91
|
-
_mime_image.add_header('Content-ID', '<{}>'.format(_image['cid']))
|
92
|
-
_message.attach(_mime_image)
|
93
|
-
|
94
|
-
else:
|
95
|
-
|
96
|
-
next
|
97
|
-
|
98
|
-
except Exception as e:
|
99
|
-
logger.exception(e)
|
100
|
-
next
|
101
|
-
|
102
|
-
# 发件人
|
103
|
-
_message['From'] = formataddr([sender.get('name'), sender.get('address')])
|
104
|
-
|
105
|
-
# 收件人
|
106
|
-
if utils.v_true(recipients, str):
|
107
|
-
_message['To'] = format_parse(recipients)
|
108
|
-
elif utils.v_true(recipients, list):
|
109
|
-
_message['To'] = ", ".join(list(map(format_parse, recipients)))
|
110
|
-
else:
|
111
|
-
logger.error('recipients error')
|
112
|
-
return False
|
113
|
-
|
114
|
-
# 主题
|
115
|
-
_message['Subject'] = subject
|
116
|
-
|
117
|
-
'''
|
118
|
-
发送邮件
|
119
|
-
|
120
|
-
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())
|
121
|
-
|
122
|
-
to_addrs = sender_to + sender_cc
|
123
|
-
https://docs.python.org/3/library/smtplib.html#smtplib.SMTP.sendmail
|
124
|
-
https://gist.github.com/AO8/c5a6f747eeeca02351152ae8dc79b537
|
125
|
-
'''
|
126
|
-
|
127
|
-
if smtp.get('ssl', False) == True:
|
128
|
-
|
129
|
-
with smtplib.SMTP_SSL(smtp.get('server'), smtp.get('port')) as _smtp:
|
130
|
-
_smtp.login(sender.get('address'), sender.get('password'))
|
131
|
-
_smtp.sendmail(sender.get('address'), recipients, _message.as_string())
|
132
|
-
|
133
|
-
else:
|
134
|
-
|
135
|
-
with smtplib.SMTP(smtp.get('server'), smtp.get('port')) as _smtp:
|
136
|
-
_smtp.login(sender.get('address'), sender.get('password'))
|
137
|
-
_smtp.sendmail(sender.get('address'), recipients, _message.as_string())
|
138
|
-
|
139
|
-
logger.success('sendemail success')
|
140
|
-
|
141
|
-
return True
|
142
|
-
|
143
|
-
except Exception as e:
|
144
|
-
logger.error('sendemail error')
|
145
|
-
logger.exception(e)
|
146
|
-
return False
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|