pandas遍历.tail切片DataFrame行报KeyError:0问题排查
问题根因
触发KeyError: 0的直接原因是pandas的索引机制:调用.tail()做行切片时,返回的子DataFrame会保留原始数据的行索引,不会自动重置为从0开始的连续序列。你用range(len(mails))生成0起始的整数作为下标取Series值时,pandas默认按索引标签匹配而非按行位置匹配,子数据里不存在0号索引,直接抛出键错误。
你代码里还存在其他会阻塞流程的连带bug:
- 变量命名冲突:将DataFrame赋值给
list,覆盖了Python内置的list类型,后续调用列表相关方法会直接报错。 - 逻辑缩进错误:注释掉的邮箱匹配代码块缩进位置不对,就算取消注释也不会在每轮循环中执行,
mail变量会出现未定义的问题。 - 语法错误:邮件正文的f-string把换行符
\n写在了字符串引号外部,运行时会直接报语法错误。 - 资源释放逻辑错误:第一轮循环发送完第一封邮件就执行
server.close()关闭SMTP连接,后续循环发送时连接已经失效。 - 收件人格式错误:对单个邮箱字符串调用
", ".join(mail)会把邮箱地址拆成单个字符拼接,完全不符合邮件头格式要求。
修复后代码
import pandas as pd import smtplib from email.mime.text import MIMEText def invio_mail(my_tailed_df): gmail_user = '###' gmail_password = '###' sent_from = gmail_user # SMTP连接初始化放在循环外,所有邮件发送完成后再关闭 server = smtplib.SMTP_SSL('smtp.gmail.com', 465) server.ehlo() server.login(gmail_user, gmail_password) df = my_tailed_df # 重置索引,丢弃原索引标签,解决索引不连续问题 df = df.reset_index(drop=True) # 用iterrows逐行遍历,不需要手动维护下标,从根源避免索引匹配错误 for idx, row in df.iterrows(): # 直接从当前行对象读取字段,无需提前拆分为单独Series customer = row['CUSTOMER'] wr = row['WR'] phone = row['PHONE'] street = row['STREET'] city = row["CITY"] mobile = row['MOBILE'] mobile2 = row['MOBILE2'] inst_code = row['INST'] # 邮箱匹配逻辑放在循环内部,逐行匹配对应收件人 if inst_code == "T138": recv_mail = "email_1@gmail.com" elif inst_code == "T139": recv_mail = "email_2@gmail.com" else: print(f"第{idx}行未匹配到对应邮箱,跳过发送") continue subject = 'My subject' # 修正f-string换行写法,所有内容放在字符串内部 body = ( f"There you go\n" f"Name: {customer}\n" f"WR: {wr}\n" f"Phone: {phone}\n" f"Street: {street}\n" f"City: {city}\n" f"Mobile: {mobile}\n" f"Mobile2: {mobile2}" ) # 用MIMEText构造标准邮件格式,避免乱码和投递失败 msg = MIMEText(body, 'plain', 'utf-8') msg['From'] = sent_from msg['To'] = recv_mail msg['Subject'] = subject try: server.sendmail(sent_from, [recv_mail], msg.as_string()) print(f'邮件已发送至{recv_mail}') except Exception as e: print(f"发送至{recv_mail}失败,错误:{str(e)}") # 所有流程结束后再关闭SMTP连接 server.quit() print("全部邮件发送流程执行完毕")
关键修改说明
- 索引问题修复:两种实现逻辑二选一即可:要么在
.tail()切片后调用.reset_index(drop=True)重置索引为0起始连续值,保留原有的下标取值写法;要么直接用df.iterrows()逐行遍历,不需要手动维护计数下标,完全规避索引不匹配问题。 - 调整SMTP连接的生命周期,避免发送中途连接被关闭。
- 修正邮件构造逻辑,使用标准MIME格式,避免文本格式错误导致的投递异常。
- 补充分支容错逻辑,未匹配到邮箱的行不会中断整个发送流程。
内容的提问来源于stack exchange,提问作者Federico
相关产品推荐
相关产品推荐

