Python手搓郵件發(fā)送客戶端
1. 簡介
這款郵件發(fā)送客戶端是一款桌面應用程序,旨在提供一個簡潔且高效的郵件發(fā)送界面,支持發(fā)送郵件、附件、定時發(fā)送以及個性化郵件正文。該應用支持通過SMTP協(xié)議發(fā)送電子郵件,提供豐富的配置選項,并支持附件管理。它還允許用戶設置郵件簽名,支持拖拽文件添加附件,能夠根據(jù)用戶設定的時間進行郵件的定時發(fā)送。界面設計采用了淺藍色主題,用戶體驗友好。
2.主要功能
2.1.郵件發(fā)送功能
- 輸入郵件賬號、授權(quán)碼、SMTP服務器、端口等信息。
- 填寫郵件收件人、抄送人、郵件標題和正文。
- 支持富文本格式郵件正文(支持HTML和圖片)。
- 可以添加附件,并在郵件中附加多個文件。
- 用戶點擊發(fā)送郵件按鈕時,send_email 函數(shù)會讀取用戶輸入的郵件信息(賬號、密碼、SMTP信息等),創(chuàng)建一個 MIME
- 格式的郵件對象。郵件正文以 HTML 格式發(fā)送,并添加附件(如果有)。
- 通過 smtplib.SMTP_SSL 連接到SMTP服務器,并使用提供的郵件賬號和授權(quán)碼登錄,最后將郵件發(fā)送出去。
2.2.個性簽名功能
允許用戶設置郵件的個性簽名,支持HTML和圖片:通過 signature_input 支持富文本,用戶可以在其中插入HTML標簽(包括 標簽)。在發(fā)送郵件時,如果個性簽名包含圖片,這些圖片會被作為附件嵌入到郵件中。
2.3.定時發(fā)送功能
用戶可以設置定時發(fā)送郵件的時間。schedule_email_send
函數(shù)會根據(jù)當前時間和設定的時間差,利用定時器(QTimer)在指定時間調(diào)用 send_email 函數(shù)發(fā)送郵件。
為了支持定時發(fā)送郵件功能,需要在現(xiàn)有代碼中添加一個定時器,允許用戶設定發(fā)送時間,并在設定的時間自動發(fā)送郵件。我們可以通過 QTimer 來實現(xiàn)定時功能。
定時發(fā)送部分:
新增了 QDateTimeEdit 輸入框,允許用戶選擇定時發(fā)送的日期和時間。
新增了一個 schedule_email_send() 函數(shù),用來計算當前時間與目標發(fā)送時間的差距,并通過
QTimer.singleShot() 在設定的時間觸發(fā)郵件發(fā)送。
定時發(fā)送郵件 按鈕將調(diào)用 schedule_email_send() 函數(shù)。
相關(guān)定時器的實現(xiàn):
使用 QTimer.singleShot() 來定時觸發(fā)郵件發(fā)送。該函數(shù)接收時間間隔(以毫秒為單位)和要執(zhí)行的回調(diào)函數(shù)(即send_email())。
2. 4.附件管理
支持通過文件選擇框或者拖拽文件添加附件。
顯示附件名稱和文件大小。
支持清除附件功能。
一鍵多選附件:
附件添加:通過 add_attachment
函數(shù),用戶可以通過文件對話框選擇一個或多個文件,添加到附件列表,并在表格中顯示文件名和文件大小。
附件清除:通過 clear_attachments 函數(shù),用戶可以清空附件列表。
附件表格:attachment_table 用于顯示附件信息,每個附件占一行,顯示文件名和大小。
使用filedialog.askopenfilenames(),允許用戶選擇多個文件。
選擇的每個文件的名稱、路徑和文件大小被添加到附件列表中。
使用tkinterdnd2庫實現(xiàn)拖拽文件到程序中。 當文件被拖拽到窗口時,會顯示附件的名稱和文件大小。
2.5.配置加載功能
應用啟動時,load_config 函數(shù)會檢查當前路徑是否存在 config.ini文件,如果存在,將從文件中讀取郵件賬號、授權(quán)碼、SMTP服務器及端口,并自動填充輸入框,且設置為只讀。
配置文件格式 (config.ini): config.ini文件應包含如下內(nèi)容:
sender_email:郵件賬號。
sender_password:授權(quán)碼。
smtp_server:SMTP服務器地址。
smtp_port:SMTP服務器端口號。
[Email] sender_email = your_email@example.com sender_password = your_authorization_code [SMTP] smtp_server = smtp.example.com smtp_port = 465
自動加載當前路徑配置文件(config.ini),填充發(fā)件人的郵件賬號、授權(quán)碼等字段信息,并設置為只讀。
2.6.主題設置和UI
使用 QVBoxLayout 和 QHBoxLayout 布局管理器,組織各個控件的排版。
使用 QPalette 設置淺藍色背景、按鈕背景和輸入框背景等顏色,并定義按鈕文本為白色,使用 Segoe UI 字體。
2.7.錯誤處理與消息框
在遇到錯誤(如SMTP連接失敗、配置文件讀取失敗等)時,使用 QMessageBox 彈出提示框顯示錯誤信息。
2.8 日志保存功能
在當前路徑生成 email_send.log日志文件,保存相關(guān)郵件發(fā)送信息等事件。
3. 運行效果
普通界面:
UI美化界面:
發(fā)送成功界面:
郵箱接收界面:
日志生成頁面:
資源列表頁面:
4.BUG修復之路
顯示發(fā)送郵件失敗,軟件報錯:getaddrinfo faied
后面檢查發(fā)現(xiàn)是郵件服務器填寫時候多敲了一個空格導致的報錯,后面在發(fā)送郵件時,在send_email函數(shù)中,使用.strip()方法去除輸入框內(nèi)容的首尾空格和TAB字符。
郵件正文通過body_text.get(“1.0”, tk.END).strip()獲取內(nèi)容時,也會清除多余的空格和TAB字符。
附件發(fā)送比如.xlsx發(fā)出去變成未命名.bin文件
當發(fā)送 .xlsx 等 Office 類型附件時,附件變成 .bin 文件的原因,通常是因為郵件的 MIME類型沒有正確指定,導致郵件客戶端無法識別文件類型并將其處理為二進制流。因此,需要確保在附件添加時指定正確的 MIME 類型和內(nèi)容類型。
對于 .xlsx 文件,我們需要確保 MIME 類型設置為application/vnd.openxmlformats-officedocument.spreadsheetml.sheet。同樣,其他Office 文件(如 .docx、.pptx)也有各自的 MIME 類型。
修改代碼:正確設置 MIME 類型
我們可以修改附件的 MIME 類型來確保文件以原格式發(fā)送。以下是如何修復這個問題:
針對 Office 文件設置正確的 MIME 類型
根據(jù)附件的擴展名自動設置 MIME 類型
主要修改:
使用 mimetypes 識別文件類型:通過 mimetypes.guess_type() 函數(shù)識別文件的 MIME
類型。如果文件類型是已知的(例如 .xlsx),就會設置正確的 MIME 類型。
create_attachment 函數(shù):這個函數(shù)根據(jù)文件類型創(chuàng)建附件并設置適當?shù)?MIME 類型。如果是 .xlsx 文件,則設置application/vnd.openxmlformats-officedocument.spreadsheetml.sheet MIME 類型。
5.部分相關(guān)源碼分享
# 讀取config.ini文件并填充輸入框 def load_config(): config_file = "config.ini" if os.path.exists(config_file): config = configparser.ConfigParser() config.read(config_file) try: sender_email = config.get("Email", "sender_email") sender_password = config.get("Email", "sender_password") smtp_server = config.get("SMTP", "smtp_server") smtp_port = config.get("SMTP", "smtp_port") # 填充輸入框并設置為只讀 sender_email_input.setText(sender_email) sender_password_input.setText(sender_password) smtp_server_input.setText(smtp_server) smtp_port_input.setText(smtp_port) # 設置輸入框為只讀 sender_email_input.setReadOnly(True) sender_password_input.setReadOnly(True) smtp_server_input.setReadOnly(True) smtp_port_input.setReadOnly(True) except Exception as e: QMessageBox.critical(window, "錯誤", f"讀取配置文件失敗: {e}") else: # 如果沒有config.ini文件,不做任何操作 pass # 發(fā)送郵件的函數(shù) def send_email(): sender_email = sender_email_input.text().strip() sender_password = sender_password_input.text().strip() smtp_server = smtp_server_input.text().strip() smtp_port = smtp_port_input.text().strip() recipient_email = recipient_input.text().strip() cc_email = cc_input.text().strip().replace(";", ",") # 替換中文分隔符 subject = subject_input.text().strip() body = body_input.toPlainText().strip() signature = signature_input.toHtml().strip() # 獲取個性簽名HTML內(nèi)容 # 將個性簽名添加到郵件正文 if signature: body += f"<br><br>{signature}" # 檢查SMTP端口是否有效 if not smtp_port.isdigit(): QMessageBox.critical(window, "錯誤", "請輸入有效的SMTP端口號!") return # 創(chuàng)建郵件 msg = MIMEMultipart("related") # 允許郵件中包含HTML內(nèi)容和附件 msg['From'] = sender_email msg['To'] = recipient_email if cc_email: msg['Cc'] = cc_email # 抄送多個郵箱 msg['Subject'] = subject # 郵件正文 msg_html = MIMEText(body, 'html', 'utf-8') # 使用HTML格式發(fā)送郵件正文 msg.attach(msg_html) # 添加附件 for file in attachments: file_path = file['path'] file_name = file['name'] mime_type, _ = mimetypes.guess_type(file_path) # 根據(jù)文件擴展名自動猜測 MIME 類型 if mime_type is None: mime_type = 'application/octet-stream' # 默認 MIME 類型 main_type, sub_type = mime_type.split('/') part = MIMEBase(main_type, sub_type) with open(file_path, 'rb') as f: part.set_payload(f.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', f'attachment; filename="{file_name}"') msg.attach(part) try: # 設置SMTP服務器 with smtplib.SMTP_SSL(smtp_server, int(smtp_port)) as server: server.login(sender_email, sender_password) # 發(fā)送郵件 server.sendmail(sender_email, [recipient_email] + (cc_email.split(',') if cc_email else []), msg.as_string()) QMessageBox.information(window, "成功", "郵件發(fā)送成功!") #clear_fields() # 發(fā)送郵件后清除輸入框和附件 except Exception as e: QMessageBox.critical(window, "錯誤", f"發(fā)送郵件失敗: {e}") # 添加附件的函數(shù) def add_attachment(): file_paths, _ = QFileDialog.getOpenFileNames(window, "選擇附件", "", "All Files (*);;Text Files (*.txt);;Image Files (*.png *.jpg *.bmp);;Excel Files (*.xlsx);;PDF Files (*.pdf)") if file_paths: for file_path in file_paths: file_name = os.path.basename(file_path) file_size = os.path.getsize(file_path) attachments.append({"name": file_name, "path": file_path, "size": file_size}) # 將附件信息添加到表格中 row_position = attachment_table.rowCount() attachment_table.insertRow(row_position) attachment_table.setItem(row_position, 0, QTableWidgetItem(file_name)) attachment_table.setItem(row_position, 1, QTableWidgetItem(f"{file_size // 1024} KB")) # 清除附件的函數(shù) def clear_attachments(): attachments.clear() attachment_table.setRowCount(0) # 清除所有輸入框的內(nèi)容和附件 def clear_fields(): sender_email_input.clear() sender_password_input.clear() smtp_server_input.clear() smtp_port_input.clear() recipient_input.clear() cc_input.clear() subject_input.clear() body_input.clear() signature_input.clear() # 清除個性簽名輸入框內(nèi)容 clear_attachments() # 清除附件列表 # 設置定時發(fā)送的函數(shù) def schedule_email_send(): send_time = send_time_input.dateTime() current_time = QDateTime.currentDateTime() if send_time <= current_time: QMessageBox.critical(window, "錯誤", "請選擇未來的時間!") return time_diff = current_time.msecsTo(send_time) # 計算定時發(fā)送的時間差 timer.singleShot(time_diff, send_email) # 定時調(diào)用發(fā)送郵件函數(shù) QMessageBox.information(window, "成功", f"郵件將在 {send_time.toString()} 發(fā)送。") # 創(chuàng)建主窗口 app = QApplication(sys.argv) window = QWidget() window.setWindowTitle("郵件發(fā)送客戶端") window.setWindowIcon(QIcon("icon.png")) # 可以設置一個圖標 window.setGeometry(100, 100, 400, 700) # 增加窗口高度,以適應新添加的個性簽名文本框 # 創(chuàng)建淺藍色主題 def set_light_blue_theme(): palette = QPalette() palette.setColor(QPalette.Background, QColor(173, 216, 230)) # 淺藍色背景 palette.setColor(QPalette.WindowText, QColor(0, 0, 0)) # 黑色文本 palette.setColor(QPalette.Button, QColor(73, 170, 160)) # 按鈕背景色為 #49AAA0 palette.setColor(QPalette.ButtonText, QColor(255, 255, 255)) # 按鈕文本為白色 palette.setColor(QPalette.Base, QColor(240, 248, 255)) # 淺藍色輸入框背景 palette.setColor(QPalette.Text, QColor(0, 0, 0)) # 黑色文本 window.setPalette(palette) set_light_blue_theme() # 設置字體為 Segoe UI font = QFont("Segoe UI", 10) window.setFont(font)
6.總結(jié)
總之這個郵件客戶端不僅提供基礎的郵件發(fā)送和附件管理功能,還集成了定時發(fā)送、個性簽名等高級功能,兼具簡潔的用戶界面和較強的功能擴展性。界面采用簡潔明了的淺藍色主題,結(jié)合了現(xiàn)代UI設計理念和豐富的郵件配置選項,適合用戶進行郵件發(fā)送和管理
以上就是Python手搓郵件發(fā)送客戶端的詳細內(nèi)容,更多關(guān)于Python郵件發(fā)送的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python最大連續(xù)區(qū)間和動態(tài)規(guī)劃
這篇文章主要介紹了Python最大連續(xù)區(qū)間和動態(tài)規(guī)劃,文章圍繞Python最大連續(xù)區(qū)間和動態(tài)規(guī)劃的相關(guān)資料展開內(nèi)容,需要的小伙伴可以參考一下2022-01-01詳解Python實現(xiàn)多進程異步事件驅(qū)動引擎
本篇文章主要介紹了詳解Python實現(xiàn)多進程異步事件驅(qū)動引擎,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08Python?datacompy?找出兩個DataFrames不同的地方
本文主要介紹了Python?datacompy?找出兩個DataFrames不同的地方,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧<BR>2022-05-05使用Python對Syslog信息進行分析并繪圖的實現(xiàn)
這篇文章主要介紹了使用Python對Syslog信息進行分析并繪圖的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04