如何防止SMTP连接超时?Python smtplib无限运行脚本密码安全处理
嘿,我正好做过类似的需求,给你整理一套靠谱的解决方案👇
针对无限运行脚本+每日发确认邮件的完整方案
一、密码安全处理:仅初始化时输入
你用getpass.getpass()的思路完全正确!这是Python标准库提供的安全输入方式,输入时不会显示明文,而且只在脚本启动时输入一次,之后密码会存在内存里供后续发送邮件使用——只要脚本不重启,就不用重复输入,完美符合你不想写死密码的需求。
二、实现每日定时发送逻辑
既然要脚本无限运行且每日执行,推荐用schedule这个轻量定时任务库,比自己写time.sleep()判断时间要直观好维护。当然如果你不想额外装库,也可以用系统级定时任务(比如Linux的cron、Windows任务计划),但脚本内定时更贴合你“无限运行”的要求。
三、防止SMTP连接超时的核心技巧
SMTP连接超时大多是因为长连接被服务器闲置断开,或者网络波动,这几个方法能有效解决:
- 每次发信重建连接:别保持长连接,每次发送邮件前重新初始化SMTP连接,发完就关闭(用
with语句自动管理连接最省心),避免长时间闲置被踢。 - 设置连接超时参数:在
smtplib.SMTP()或SMTP_SSL()初始化时加上timeout参数,比如smtplib.SMTP_SSL('smtp.example.com', 465, timeout=30),避免程序无限等待卡死。 - 添加重试机制:用
try-except捕获超时、连接失败等异常,重试2-3次,提升容错率。
四、完整可运行示例代码
import smtplib import getpass import schedule import time from email.mime.text import MIMEText from email.header import Header # 初始化邮箱信息,仅启动时输入一次密码 def init_email_config(): global sender_addr, auth_code, receiver_addr sender_addr = "your_sender@example.com" # 安全输入授权码/密码,不显示明文 auth_code = getpass.getpass("请输入邮箱授权码/密码: ") receiver_addr = "your_receiver@example.com" # 发送确认邮件的核心函数 def send_daily_confirmation(): try: # 构建邮件内容 email_content = "今日任务指定步骤已完成,请查收确认!" msg = MIMEText(email_content, 'plain', 'utf-8') msg['From'] = Header("任务自动化通知", 'utf-8') msg['To'] = Header("负责人", 'utf-8') msg['Subject'] = Header("每日任务完成确认", 'utf-8') # 每次发信重建连接,避免长连接超时 with smtplib.SMTP_SSL('smtp.example.com', 465, timeout=30) as smtp_server: smtp_server.login(sender_addr, auth_code) smtp_server.sendmail(sender_addr, receiver_addr, msg.as_string()) print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 确认邮件发送成功") except smtplib.SMTPException as e: print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 邮件发送失败: {str(e)}") # 重试2次,每次间隔5秒 for retry_count in range(2): time.sleep(5) try: with smtplib.SMTP_SSL('smtp.example.com', 465, timeout=30) as smtp_server: smtp_server.login(sender_addr, auth_code) smtp_server.sendmail(sender_addr, receiver_addr, msg.as_string()) print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 第{retry_count+1}次重试成功") break except smtplib.SMTPException as retry_err: print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 第{retry_count+1}次重试失败: {str(retry_err)}") except Exception as general_err: print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] 发生未知错误: {str(general_err)}") # 主程序:初始化+启动定时任务 def main(): init_email_config() # 设置每日发送时间,比如早上9点 schedule.every().day.at("09:00").do(send_daily_confirmation) print("脚本已启动,将每日09:00自动发送任务确认邮件...") # 无限循环运行定时任务 while True: schedule.run_pending() time.sleep(60) # 每分钟检查一次任务状态 if __name__ == "__main__": main()
额外提醒
- 如果你用的是QQ、163等第三方邮箱,记得开启POP3/SMTP服务,并且用授权码代替登录密码(授权码在邮箱设置里生成),比直接用密码更安全,也能避免一些登录限制。
- 如果需要脚本后台运行,Linux可以用
nohup python your_script.py &,Windows可以把脚本打包成服务或者用后台运行工具,防止终端关闭后脚本停止。 - 定时任务精度:示例里每分钟检查一次任务,完全满足每日定时的需求,要是需要更高精度,可以把
time.sleep(60)改成time.sleep(10)。
内容的提问来源于stack exchange,提问作者agftrading
相关产品推荐
相关产品推荐

