如何将SMTP服务器状态保存到文件以实现免重复登录?
解决无法保存SMTP服务器状态以避免重复登录的问题
为什么pickle不可行?
SMTP对象包含SSLSocket这类与系统底层网络资源绑定的对象,这类实时连接状态无法被序列化(pickle),所以直接保存整个server实例必然报错。
可行方案
方案1:进程内复用连接
如果是在同一个进程内多次发送邮件,直接维护一个全局的SMTP对象,检测连接状态失效后再重新初始化:
import smtplib, ssl class GmailSMTPManager: def __init__(self, user, password): self.user = user self.password = password self._server = None def get_server(self): # 检查连接是否存活 if self._server is None: self._init_server() else: try: self._server.noop() # 发送空命令检测连接状态 except smtplib.SMTPServerDisconnected: self._init_server() return self._server def _init_server(self): self._server = smtplib.SMTP(host="smtp.gmail.com", port=587) self._server.ehlo() self._server.starttls(context=ssl.create_default_context()) self._server.ehlo() self._server.login(user=self.user, password=self.password) # 使用示例 manager = GmailSMTPManager("abc@gmail.com", "abcdefghijklmnop") # 首次调用初始化并登录 server = manager.get_server() server.sendmail("abc@gmail.com", "recipient@example.com", "邮件内容") # 后续调用复用存活连接 server = manager.get_server() server.sendmail("abc@gmail.com", "another@example.com", "另一封邮件")
方案2:保存登录凭证而非连接状态
SMTP连接本身有超时限制,即使能序列化保存,过一段时间也会失效。更可靠的方式是保存登录凭证,每次需要发邮件时重新建立连接(带状态检测):
import smtplib, ssl import json import os # 保存凭证到本地文件 def save_credentials(user, password, filepath="gmail_creds.json"): with open(filepath, "w") as f: json.dump({"user": user, "password": password}, f) # 加载本地凭证 def load_credentials(filepath="gmail_creds.json"): if os.path.exists(filepath): with open(filepath, "r") as f: return json.load(f) return None # 获取可用的SMTP服务器连接 def get_active_smtp(credentials): server = smtplib.SMTP(host="smtp.gmail.com", port=587) try: server.noop() except smtplib.SMTPServerDisconnected: # 连接失效,重新登录 server.ehlo() server.starttls(context=ssl.create_default_context()) server.ehlo() server.login(credentials["user"], credentials["password"]) return server # 使用示例 # 首次运行保存凭证 save_credentials("abc@gmail.com", "abcdefghijklmnop") # 后续运行加载凭证并获取连接 creds = load_credentials() if creds: smtp_server = get_active_smtp(creds) smtp_server.sendmail("abc@gmail.com", "target@example.com", "测试邮件")
注意:Gmail用户建议使用应用专用密码(开启两步验证后可创建),而非邮箱原始密码,提升账号安全性。
内容的提问来源于stack exchange,提问作者brownfox2k6
相关产品推荐
相关产品推荐

