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.
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
7
- Requires-Python: >=3.11
7
+ Requires-Python: >=3.10
8
8
  License-File: LICENSE
@@ -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
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ezKit
3
- Version: 1.7.1
3
+ Version: 1.7.3
4
4
  Summary: Easy Kit
5
5
  Author: septvean
6
6
  Author-email: septvean@gmail.com
7
- Requires-Python: >=3.11
7
+ Requires-Python: >=3.10
8
8
  License-File: LICENSE
@@ -3,13 +3,13 @@ from setuptools import find_packages, setup
3
3
 
4
4
  setup(
5
5
  name='ezKit',
6
- version='1.7.1',
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.11',
12
+ python_requires='>=3.10',
13
13
  # install_requires=[
14
14
  # 'loguru>=0.7.0',
15
15
  # 'tomlkit>=0.12.0'
@@ -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