Python利用SMTP發(fā)送郵件的常見問題與解決方案詳解
引言
在自動(dòng)化辦公和系統(tǒng)開發(fā)中,郵件發(fā)送功能是常見的需求。無論是發(fā)送通知、報(bào)告,還是傳輸文件,Python的smtplib和email庫提供了便捷的實(shí)現(xiàn)方式。然而,在實(shí)際開發(fā)中,開發(fā)者常會(huì)遇到各種SMTP錯(cuò)誤,如(-1, b'\x00\x00\x00')、AttributeError('characters_written')等,這些問題往往讓人束手無策。
本文將從實(shí)際案例出發(fā),分析常見的SMTP錯(cuò)誤,并提供完整的解決方案,幫助開發(fā)者快速定位和解決問題。同時(shí),我們還會(huì)優(yōu)化代碼,使其更健壯、更易于維護(hù)。
1. 問題背景
在Python中,使用smtplib
發(fā)送郵件時(shí),通常會(huì)遇到兩類問題:
- 連接與認(rèn)證問題(如授權(quán)碼錯(cuò)誤、SMTP服務(wù)器拒絕連接)
- 數(shù)據(jù)編碼與協(xié)議問題(如SSL/TLS握手失敗、附件編碼錯(cuò)誤)
以下是一個(gè)典型的郵件發(fā)送代碼,它可能會(huì)觸發(fā)上述錯(cuò)誤:
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication import os import logging logger = logging.getLogger(__name__) def send_email_with_attachment(filepath, receiver_email): sender_email = "your_email@qq.com" password = "your_authorization_code" # QQ郵箱授權(quán)碼 smtp_server = "smtp.qq.com" smtp_port = 465 # QQ郵箱SSL端口 msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = receiver_email msg['Subject'] = "文件處理結(jié)果通知" # 郵件正文 msg.attach(MIMEText("請(qǐng)查收附件", 'plain')) # 添加附件 try: with open(filepath, "rb") as f: part = MIMEApplication(f.read(), Name=os.path.basename(filepath)) part['Content-Disposition'] = f'attachment; filename="{os.path.basename(filepath)}"' msg.attach(part) except FileNotFoundError: logger.error("附件文件不存在") return False # 發(fā)送郵件 try: with smtplib.SMTP_SSL(smtp_server, smtp_port) as server: server.login(sender_email, password) server.sendmail(sender_email, receiver_email, msg.as_string()) return True except Exception as e: logger.error(f"發(fā)送郵件失敗: {e}", exc_info=True) return False
運(yùn)行此代碼時(shí),可能會(huì)遇到以下錯(cuò)誤:
2. 常見錯(cuò)誤及解決方案
錯(cuò)誤1:SMTPResponseException: (-1, b'\x00\x00\x00')
錯(cuò)誤原因
- 授權(quán)碼錯(cuò)誤或已過期。
- SMTP服務(wù)器(如QQ郵箱)檢測(cè)到異常登錄,拒絕連接。
- 網(wǎng)絡(luò)或防火墻攔截了SMTP請(qǐng)求。
解決方案
1.檢查授權(quán)碼
登錄QQ郵箱 → 設(shè)置 → 賬戶 → 生成新的授權(quán)碼,并替換代碼中的password。
2.更換SMTP端口(推薦使用587+TLS)
QQ郵箱支持465(SSL)和587(TLS),后者更穩(wěn)定:
smtp_port = 587 # 改用TLS端口 with smtplib.SMTP(smtp_server, smtp_port) as server: server.starttls() # 啟用TLS加密 server.login(sender_email, password)
3.檢查網(wǎng)絡(luò)環(huán)境
關(guān)閉防火墻或切換網(wǎng)絡(luò)(如使用手機(jī)熱點(diǎn)測(cè)試)。
錯(cuò)誤2:AttributeError('characters_written')
錯(cuò)誤原因
- Python 3.10+ 與 SMTP_SSL 的兼容性問題。
- SSL/TLS握手失敗,可能是由于OpenSSL版本不匹配。
解決方案
1.改用starttls()(推薦)
避免使用SMTP_SSL,改用SMTP + starttls():
with smtplib.SMTP(smtp_server, 587) as server: server.starttls() # 顯式啟用TLS server.login(sender_email, password)
2.降級(jí)Python或升級(jí)依賴庫
如果仍報(bào)錯(cuò),嘗試降級(jí)到Python 3.9,或更新pyopenssl:
pip install --upgrade pyopenssl
3. 優(yōu)化后的郵件發(fā)送代碼
結(jié)合上述解決方案,優(yōu)化后的代碼如下:
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication import os import logging import base64 logger = logging.getLogger(__name__) def send_email_with_attachment(filepath, receiver_email): """發(fā)送帶附件的郵件(支持QQ郵箱)""" sender_email = "your_email@qq.com" password = "your_authorization_code" # 替換為最新授權(quán)碼 smtp_server = "smtp.qq.com" smtp_port = 587 # 使用TLS端口 # 檢查附件是否存在 if not os.path.exists(filepath): logger.error(f"附件文件不存在: {filepath}") return False # 創(chuàng)建郵件內(nèi)容 msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = receiver_email msg['Subject'] = "文件處理結(jié)果通知" msg.attach(MIMEText("請(qǐng)查收附件", 'plain')) # 添加附件 try: with open(filepath, "rb") as f: part = MIMEApplication(f.read(), Name=os.path.basename(filepath)) part['Content-Disposition'] = f'attachment; filename="{os.path.basename(filepath)}"' msg.attach(part) except Exception as e: logger.error(f"附件處理失敗: {e}") return False # 發(fā)送郵件(使用TLS) try: with smtplib.SMTP(smtp_server, smtp_port) as server: server.starttls() # 啟用TLS加密 server.login(sender_email, password) server.sendmail(sender_email, receiver_email, msg.as_string()) logger.info("郵件發(fā)送成功") return True except smtplib.SMTPException as e: logger.error(f"SMTP錯(cuò)誤: {e}") except Exception as e: logger.error(f"未知錯(cuò)誤: {e}", exc_info=True) return False
優(yōu)化點(diǎn)
1.更健壯的異常處理
區(qū)分SMTPException和其他異常,便于排查問題。
2.附件預(yù)檢查
發(fā)送前驗(yàn)證附件是否存在。
3.日志記錄
使用logging記錄詳細(xì)錯(cuò)誤信息。
4. SMTP調(diào)試技巧
手動(dòng)測(cè)試SMTP連接
使用openssl命令行工具測(cè)試SMTP服務(wù)是否可用:
openssl s_client -connect smtp.qq.com:587 -starttls smtp -crlf
輸入以下命令(替換為你的郵箱和授權(quán)碼):
EHLO test
AUTH LOGIN
<base64編碼的郵箱> # 示例:echo -n "your_email@qq.com" | base64
<base64編碼的授權(quán)碼>
QUIT
如果返回235 Authentication successful,說明SMTP配置正確。
檢查防火墻
在Windows上,運(yùn)行以下命令放行SMTP端口:
netsh advfirewall firewall add rule name="SMTP" dir=in action=allow protocol=TCP localport=587
5. 總結(jié)與最佳實(shí)踐
常見問題總結(jié)
錯(cuò)誤 | 原因 | 解決方案 |
---|---|---|
(-1, b'\x00\x00\x00') | 授權(quán)碼錯(cuò)誤/SMTP拒絕 | 更新授權(quán)碼,改用starttls() |
AttributeError('characters_written') | Python 3.10+兼容性問題 | 降級(jí)Python或改用SMTP + starttls() |
SSL: WRONG_VERSION_NUMBER | SSL/TLS配置錯(cuò)誤 | 使用starttls() + 端口587 |
最佳實(shí)踐
- 使用TLS(端口587)代替SSL(端口465),兼容性更好。
- 定期更新授權(quán)碼,避免因過期導(dǎo)致發(fā)送失敗。
- 添加日志記錄,便于排查問題。
- 手動(dòng)測(cè)試SMTP連接,確保服務(wù)器可用。
通過本文的分析和優(yōu)化,你應(yīng)該能夠解決大多數(shù)Python郵件發(fā)送問題。如果你的場(chǎng)景涉及更復(fù)雜的需求(如批量發(fā)送、HTML郵件),可以進(jìn)一步擴(kuò)展代碼邏輯。
到此這篇關(guān)于Python利用SMTP發(fā)送郵件的常見問題與解決方案詳解的文章就介紹到這了,更多相關(guān)Python SMTP發(fā)送郵件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PyQt5?python?數(shù)據(jù)庫?表格動(dòng)態(tài)增刪改詳情
這篇文章主要介紹了PyQt5?python?數(shù)據(jù)庫?表格動(dòng)態(tài)增刪改詳情,首先手動(dòng)連接數(shù)據(jù)庫與下一個(gè)的程序連接數(shù)據(jù)庫是獨(dú)立的2個(gè)部分,下面來看看文章的詳細(xì)介紹2022-01-01TensorFlow 輸出checkpoint 中的變量名與變量值方式
今天小編就為大家分享一篇TensorFlow 輸出checkpoint 中的變量名與變量值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-02-02Python中隨機(jī)數(shù)生成random庫實(shí)戰(zhàn)
本文介紹了Python的random庫,介紹了生成隨機(jī)整數(shù)、浮點(diǎn)數(shù)、序列隨機(jī)抽樣等基本功能,以及設(shè)置隨機(jī)種子、控制概率分布等高級(jí)技巧,通過多個(gè)實(shí)用示例,感興趣的可以了解一下2024-11-11Windows系統(tǒng)下Chromedriver.exe安裝及配置詳細(xì)教程
ChromeDriver.exe是一款實(shí)用的chrome瀏覽器驅(qū)動(dòng)工具,能夠用于自動(dòng)化測(cè)試、網(wǎng)絡(luò)爬蟲和操作瀏覽器,其主要作用是模擬瀏覽器操作,下面這篇文章主要給大家介紹了關(guān)于Windows系統(tǒng)下Chromedriver.exe安裝及配置的相關(guān)資料,需要的朋友可以參考下2023-11-11python實(shí)現(xiàn)給微信指定好友定時(shí)發(fā)送消息
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)給微信指定好友定時(shí)發(fā)消息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04使用Python設(shè)置,更新和獲取Excel單元格的值
Excel工作簿作為一款廣泛使用的數(shù)據(jù)管理工具,與Python相結(jié)合,可以使得自動(dòng)化處理大量數(shù)據(jù)成為可能,本文將演示如何使用Python設(shè)置、更新以及獲取Excel文件中單元格的值,希望對(duì)大家有所幫助2024-10-10Python?Pygame實(shí)戰(zhàn)之五款童年經(jīng)典游戲合集
本文為大家總結(jié)了五款利用Python+Pygame實(shí)現(xiàn)的童年經(jīng)典游戲:推箱子、滑雪、八分音符醬、保衛(wèi)蘿卜和飛機(jī)大戰(zhàn),快跟隨小編一起學(xué)習(xí)一下2022-04-04