UtilityLibAPI 1.2512.501__tar.gz → 1.2512.503__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.
Files changed (17) hide show
  1. {utilitylibapi-1.2512.501/src/UtilityLibAPI.egg-info → utilitylibapi-1.2512.503}/PKG-INFO +1 -1
  2. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/pyproject.toml +1 -1
  3. utilitylibapi-1.2512.501/src/UtilityLibAPI/MailSenderLib-Original.py → utilitylibapi-1.2512.503/src/UtilityLibAPI/MailSenderLib.py +68 -1
  4. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503/src/UtilityLibAPI.egg-info}/PKG-INFO +1 -1
  5. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI.egg-info/SOURCES.txt +0 -1
  6. utilitylibapi-1.2512.501/src/UtilityLibAPI/MailSenderLib.py +0 -245
  7. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/LICENSE +0 -0
  8. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/README.md +0 -0
  9. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/setup.cfg +0 -0
  10. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI/Archive7zLib.py +0 -0
  11. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI/EnDeCodeLib.py +0 -0
  12. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI/ExtWrapper7zLib.py +0 -0
  13. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI/SessionVARLib.py +0 -0
  14. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI/__init__.py +0 -0
  15. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI.egg-info/dependency_links.txt +0 -0
  16. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI.egg-info/requires.txt +0 -0
  17. {utilitylibapi-1.2512.501 → utilitylibapi-1.2512.503}/src/UtilityLibAPI.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UtilityLibAPI
3
- Version: 1.2512.501
3
+ Version: 1.2512.503
4
4
  Summary: UtilityLibAPI Python package
5
5
  Author-email: James Lin <tylin123@ms27.hinet.net>
6
6
  License: Copyright (c) 2025 James Lin **UtilityLibAPI**
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "UtilityLibAPI"
7
- version = "1.2512.0501"
7
+ version = "1.2512.0503"
8
8
  description = "UtilityLibAPI Python package"
9
9
  authors = [
10
10
  { name="James Lin", email="tylin123@ms27.hinet.net" }
@@ -35,6 +35,74 @@ class CLASS_MailSender:
35
35
  # ======================================================================
36
36
  self.OnAfterSendSuccess: Optional[Callable[[str], None]] = None
37
37
  self.OnAfterSendFailure: Optional[Callable[[str], None]] = None
38
+ # ============================================================
39
+ # ⭐⭐ 新增:維持 SMTP 連線用變數
40
+ # ============================================================
41
+ self.CVobj_Server: Optional[smtplib.SMTP] = None
42
+
43
+ # ################################################################################
44
+ # [預防 Mail Server 中斷連線]
45
+ # 手動控制連線
46
+ # mailer.CUF_Open()
47
+ # mailer.CUF_SendMail(...)
48
+ # mailer.CUF_Close()
49
+ # ------------------------------------------------------------
50
+ # 每 5 分鐘預防性重連
51
+ # mailer.CUF_Reconnect()
52
+ # ------------------------------------------------------------
53
+ # 如果 SendMail 失敗,要重連
54
+ # if not mailer.CUF_SendMail(...):
55
+ # mailer.CUF_Reconnect()
56
+ # ################################################################################
57
+
58
+ # ================================================================================
59
+ # ⭐⭐⭐ 新增函數:CUF_Open() ⭐⭐⭐
60
+ # ================================================================================
61
+ def CUF_Open(self) -> bool:
62
+ """建立 SMTP 連線(長連線模式)"""
63
+ try:
64
+ if self.CVobj_Server:
65
+ return True
66
+
67
+ if self.Pmb_UseSSL:
68
+ server = smtplib.SMTP_SSL(self.Pms_SMTP_Server, self.Pmi_Port)
69
+ else:
70
+ server = smtplib.SMTP(self.Pms_SMTP_Server, self.Pmi_Port)
71
+ server.ehlo()
72
+ server.starttls()
73
+
74
+ server.login(self.Pms_Account, self.Pms_Password)
75
+ self.CVobj_Server = server
76
+ return True
77
+ except Exception as e:
78
+ print("❌ CUF_Open Error:", e)
79
+ self.CVobj_Server = None
80
+ return False
81
+
82
+
83
+ # ================================================================================
84
+ # ⭐⭐⭐ 新增函數:CUF_Close() ⭐⭐⭐
85
+ # ================================================================================
86
+ def CUF_Close(self):
87
+ """關閉 SMTP 長連線"""
88
+ try:
89
+ if self.CVobj_Server:
90
+ try:
91
+ self.CVobj_Server.quit()
92
+ except:
93
+ pass
94
+ self.CVobj_Server = None
95
+ except:
96
+ self.CVobj_Server = None
97
+
98
+
99
+ # ================================================================================
100
+ # ⭐⭐⭐ 新增函數:CUF_Reconnect() ⭐⭐⭐
101
+ # ================================================================================
102
+ def CUF_Reconnect(self) -> bool:
103
+ """強制重新連線"""
104
+ self.CUF_Close()
105
+ return self.CUF_Open()
38
106
 
39
107
 
40
108
  #------------------------------------------------------------
@@ -152,7 +220,6 @@ class CLASS_MailSender:
152
220
  return False
153
221
 
154
222
 
155
-
156
223
  # ================================================================================
157
224
  # [範例]
158
225
  # 匯入剛才寫好的 CLASS_MailSender
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UtilityLibAPI
3
- Version: 1.2512.501
3
+ Version: 1.2512.503
4
4
  Summary: UtilityLibAPI Python package
5
5
  Author-email: James Lin <tylin123@ms27.hinet.net>
6
6
  License: Copyright (c) 2025 James Lin **UtilityLibAPI**
@@ -5,7 +5,6 @@ setup.cfg
5
5
  src/UtilityLibAPI/Archive7zLib.py
6
6
  src/UtilityLibAPI/EnDeCodeLib.py
7
7
  src/UtilityLibAPI/ExtWrapper7zLib.py
8
- src/UtilityLibAPI/MailSenderLib-Original.py
9
8
  src/UtilityLibAPI/MailSenderLib.py
10
9
  src/UtilityLibAPI/SessionVARLib.py
11
10
  src/UtilityLibAPI/__init__.py
@@ -1,245 +0,0 @@
1
- import smtplib
2
- import socket
3
- import ssl
4
- import time
5
- from email.mime.text import MIMEText
6
- from email.mime.multipart import MIMEMultipart
7
- from email.mime.application import MIMEApplication
8
- from typing import List, Optional
9
-
10
-
11
- # ============================================================================
12
- # CLASS: MailSender
13
- # ============================================================================
14
- class CLASS_MailSender:
15
- def __init__(self,
16
- Pms_SMTP_Server : str,
17
- Pmi_Port : int,
18
- Pms_Account : str,
19
- Pms_Password : str,
20
- Pmb_UseSSL : bool = False,
21
- Pmi_TimeoutSec : int = 10, # ★ 新增: Timeout(秒)
22
- Pmi_RetryCount : int = 3, # ★ 新增: 重試次數
23
- Pmi_RetryDelay : int = 2): # ★ 新增: 每次重試間隔
24
-
25
- self.SMTP_Server = Pms_SMTP_Server
26
- self.SMTP_Port = Pmi_Port
27
- self.SMTP_Account = Pms_Account
28
- self.SMTP_Password = Pms_Password
29
- self.UseSSL = Pmb_UseSSL
30
-
31
- self.TimeoutSec = Pmi_TimeoutSec
32
- self.RetryCount = Pmi_RetryCount
33
- self.RetryDelay = Pmi_RetryDelay
34
-
35
- self.OnAfterSendSuccess = None
36
- self.OnAfterSendFailure = None
37
-
38
-
39
- # ============================================================================
40
- # FUNC: Internal – 建立 SMTP 連線(有 timeout + retry)
41
- # ============================================================================
42
- def __CUF_OpenSMTP(self):
43
- last_error = ""
44
-
45
- for retry in range(1, self.RetryCount + 1):
46
- try:
47
- socket.setdefaulttimeout(self.TimeoutSec)
48
-
49
- if self.UseSSL:
50
- context = ssl.create_default_context()
51
- smtp = smtplib.SMTP_SSL(self.SMTP_Server,
52
- self.SMTP_Port,
53
- timeout=self.TimeoutSec,
54
- context=context)
55
- else:
56
- smtp = smtplib.SMTP(self.SMTP_Server,
57
- self.SMTP_Port,
58
- timeout=self.TimeoutSec)
59
- smtp.starttls()
60
-
61
- smtp.login(self.SMTP_Account, self.SMTP_Password)
62
- return smtp # ★ 成功
63
-
64
- except Exception as e:
65
- last_error = str(e)
66
- print(f"[警告] SMTP 連線失敗(第 {retry}/{self.RetryCount} 次),原因:{e}")
67
-
68
- if retry < self.RetryCount:
69
- time.sleep(self.RetryDelay)
70
-
71
- # ---------------------------------------------------------------------------------
72
- # ★ 最後一次仍失敗 → 回傳 None 與最後錯誤訊息
73
- return None, last_error
74
-
75
-
76
- # ============================================================================
77
- # FUNC: 寄送郵件(含 retry)
78
- # ============================================================================
79
- def CUF_SendMail(self,
80
- Pms_Subject : str,
81
- Pms_BodyText : str,
82
- Pms_BodyHTML : Optional[str] = None,
83
- Pms_From : Optional[str] = None,
84
- Pobj_To : Optional[List[str]] = None,
85
- Pobj_Bcc : Optional[List[str]] = None,
86
- Pobj_Attachments : Optional[List[str]] = None) -> bool:
87
-
88
- if Pobj_To is None:
89
- Pobj_To = []
90
-
91
- if Pobj_Bcc is None:
92
- Pobj_Bcc = []
93
-
94
- # =========================================================================
95
- # 組合 MIME
96
- # =========================================================================
97
- msg = MIMEMultipart("alternative")
98
- msg["Subject"] = Pms_Subject
99
- msg["From"] = Pms_From if Pms_From else self.SMTP_Account
100
- msg["To"] = ", ".join(Pobj_To)
101
-
102
- msg.attach(MIMEText(Pms_BodyText, "plain", "utf-8"))
103
-
104
- if Pms_BodyHTML:
105
- msg.attach(MIMEText(Pms_BodyHTML, "html", "utf-8"))
106
-
107
- # =========================================================================
108
- # 附件
109
- # =========================================================================
110
- if Pobj_Attachments:
111
- for file_path in Pobj_Attachments:
112
- try:
113
- with open(file_path, "rb") as fp:
114
- part = MIMEApplication(fp.read())
115
- part.add_header('Content-Disposition',
116
- 'attachment',
117
- filename=file_path.split("\\")[-1])
118
- msg.attach(part)
119
- except Exception as e:
120
- err = f"附件讀取失敗:{file_path}, Error={e}"
121
- print("[錯誤] " + err)
122
- if self.OnAfterSendFailure:
123
- self.OnAfterSendFailure(err)
124
- return False
125
-
126
- # =========================================================================
127
- # 寄送(含 retry)
128
- # =========================================================================
129
- last_error = ""
130
-
131
- for retry in range(1, self.RetryCount + 1):
132
- smtp = None
133
- try:
134
- smtp, err = self.__CUF_OpenSMTP()
135
- if smtp is None:
136
- last_error = err
137
- raise Exception(err)
138
-
139
- smtp.sendmail(msg["From"], Pobj_To + Pobj_Bcc, msg.as_string())
140
- smtp.quit()
141
-
142
- if self.OnAfterSendSuccess:
143
- self.OnAfterSendSuccess(Pms_Subject)
144
- return True
145
-
146
- except Exception as e:
147
- last_error = str(e)
148
- print(f"[警告] 寄送失敗(第 {retry}/{self.RetryCount} 次): {e}")
149
-
150
- if smtp:
151
- try:
152
- smtp.quit()
153
- except:
154
- pass
155
-
156
- if retry < self.RetryCount:
157
- time.sleep(self.RetryDelay)
158
-
159
- # =========================================================================
160
- # 全部 retry 失敗
161
- # =========================================================================
162
- if self.OnAfterSendFailure:
163
- self.OnAfterSendFailure(last_error)
164
-
165
- return False
166
-
167
-
168
- # ================================================================================
169
- # [範例]
170
- # 匯入剛才寫好的 CLASS_MailSender
171
- #from MailSender import CLASS_MailSender # 假設你把上面的 class 儲存為 MailSender.py
172
-
173
- def GE_OnSendSuccess(Pms_Subject : str):
174
- print("[事件]:成功寄出了!");
175
-
176
-
177
- def GE_OnSendFailure(Pms_ErrMsg : str):
178
- print("[事件]: 寄送失敗 ...");
179
- print("Err Msg:"+ Pms_ErrMsg);
180
-
181
- if(__name__ == "__main__"):
182
- # === 初始化郵件傳送物件 ===
183
- mailer = CLASS_MailSender(
184
- Pms_SMTP_Server="mxr.hxxxt.xxt",
185
- Pmi_Port=465,
186
- Pms_Account="xxxxch.xxz@xxa.xxxet.xxt",
187
- Pms_Password="xxxxxxxxx",
188
- Pmb_UseSSL=True
189
- )
190
-
191
- mailer.OnAfterSendSuccess = GE_OnSendSuccess;
192
- mailer.OnAfterSendFailure = GE_OnSendFailure;
193
-
194
- # === 郵件收件者設定 ===
195
- ml_To = ["gxxx4@goxxxx.bxz", "xxxxnxxx@xx27.xxxxx.xxt"]
196
- ml_Cc = ["exxxxxx3@hotmail.com.tw"]
197
- ml_Bcc = ["jxxxxxx.xxx@mxx.xxxet.xet"] # 密件副本,不會顯示在郵件中
198
-
199
- # === 郵件主題與內容 ===
200
- ms_Subject = "團隊週報通知 有事件 wahaha 123*()F"
201
-
202
- ms_BodyText = """
203
- 這是一封自動寄出的團隊週報通知。
204
- 請參閱附加的 PDF 檔或 HTML 內文。
205
- """
206
-
207
- ms_BodyHTML = """
208
- <html>
209
- <body style="font-family: Microsoft JhengHei;">
210
- <h2 style="color: green;">🌟 團隊週報</h2>
211
- <p>各位同仁您好:</p>
212
- <p>以下為本週重點摘要:</p>
213
- <ul>
214
- <li>完成模組 A 測試</li>
215
- <li>修正 ERP 匯出問題</li>
216
- <li>新增客戶報表功能</li>
217
- </ul>
218
- <p>詳細報表請參閱附件。</p>
219
- <p style="color: gray;">系統自動寄出,請勿回覆。</p>
220
- </body>
221
- </html>
222
- """
223
-
224
- # === 附件路徑 ===
225
- ml_Attachments = [
226
- "X:\\TEMP\\112年縣檸檬幼申報收入.jpg",
227
- "X:\\TEMP\\CR-6000-75通訊表.xls"
228
- ]
229
-
230
- # === 寄送 ===
231
- mb_OK = mailer.CUF_SendMail(
232
- Pms_Subject=ms_Subject,
233
- Pms_BodyText=ms_BodyText,
234
- Pms_BodyHTML=ms_BodyHTML,
235
- Pms_From = "太棒了!!a會觸發事件",
236
- Pobj_To=ml_To,
237
- Pobj_Cc=ml_Cc,
238
- Pobj_Bcc=ml_Bcc,
239
- Pobj_Attachments=ml_Attachments
240
- )
241
-
242
- if mb_OK:
243
- print("✅ 多人郵件已成功寄出!")
244
- else:
245
- print("❌ 寄送失敗,請檢查設定。")