遍历DataFrame批量发邮件多次迭代后出现smtplib.SMTPServerDisconnected错误求助
解决遍历DataFrame发送邮件时的
smtplib.SMTPServerDisconnected错误 我明白你在批量发送邮件时遇到了服务器断开连接的问题,这大概率是因为你每次循环都重复创建并关闭SMTP连接,频繁的连接/断开操作很容易触发邮件服务器(比如Gmail)的限制,导致连接被强制中断。另外你的代码里还有几处小问题需要修正,下面一步步来解决:
问题根源分析
- 频繁创建销毁连接:每次循环都调用
smtplib.SMTP_SSL()新建连接,发送后立刻server.quit()关闭,短时间内的这类操作会被服务器判定为异常行为,直接断开连接。 - 循环逻辑漏洞:原代码中
while i<=len(df)的i既没有初始化,也没有在循环内递增,会导致无限循环,进一步加重服务器连接压力。 - 重复IO浪费:每次循环都重复读取同一个附件文件,虽然不影响功能,但会额外消耗IO资源。
修复后的完整代码
import pandas as pd import os import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.header import Header filename = "my_excel.xlsx" df = pd.read_excel(filename, sheet_name='Sheet1') user = 'my_mail' app_password = 'password' host = 'smtp.gmail.com' port = 465 subject = 'Proof' attachment = "attachment.pdf" # 提前读取附件内容,避免循环内重复IO操作 with open(attachment, 'rb') as f: attachment_content = f.read() att_name = os.path.basename(attachment) # 仅创建一次SMTP连接,复用连接发送所有邮件 server = smtplib.SMTP_SSL(host, port) try: server.login(user, app_password) # 用iterrows()安全遍历DataFrame每一行 for idx, row in df.iterrows(): if row['Status'] == 'vencido': text = 'my_text' to = row['email'] message = MIMEMultipart() message['From'] = Header(user) message['To'] = Header(to) message['Subject'] = Header(subject) content_txt = text message.attach(MIMEText(content_txt, 'plain', 'utf-8')) # 构造附件(复用提前读取的内容) att1 = MIMEText(attachment_content, 'base64', 'utf-8') att1['Content-Type'] = 'application/octet-stream' att1['Content-Disposition'] = f'attachment; filename="{att_name}"' message.attach(att1) # 发送邮件 server.sendmail(user, to, message.as_string()) print(f"邮件已成功发送到 {to}") finally: # 无论是否出现异常,最后统一关闭连接 server.quit()
关键改进说明
- 复用SMTP连接:在循环外创建一次连接并登录,用它完成所有邮件发送后再关闭,大幅减少连接次数,避免触发服务器限制。
- 安全遍历DataFrame:使用
iterrows()遍历每一行,比直接索引更安全,同时解决了原代码中i未初始化的问题。 - 优化附件读取:提前读取一次附件内容,循环内直接复用,节省IO资源。
- 异常安全处理:用
try...finally确保连接一定会被正确关闭,避免资源泄漏。
额外建议
如果需要发送的邮件数量非常多(比如几百上千封),建议在每发送10-20封后加入短暂休眠(import time; time.sleep(2)),避免给服务器造成过大压力;另外Gmail用户需要确保已开启2FA并使用App密码登录,或者开启“不太安全的应用访问”(后者不推荐),否则会被拒绝登录。
内容的提问来源于stack exchange,提问作者Andrés Reyes
相关产品推荐
相关产品推荐

