You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 00:54:28