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

使用imaplib读取LiberoMail的OTP代码报IndexError问题求助

LiberoMail 读取Social标签OTP IndexError 排查修复

执行otp_split = [str(i) for i in str(otp[0])]抛出索引越界,本质是get_otp()函数返回的otp是空列表,没有成功提取到验证码,空列表访问第一个元素必然报错。导致提取失败的具体问题点如下:

  • 文件夹选择错误:需求是读取「Social」标签邮件,但代码中imap.select("Inbox")选中的是收件箱根目录,没有进入Social标签对应的IMAP文件夹,根本检索不到目标邮件。
  • 异常被全量吞掉:代码中用了无任何日志输出的裸except,正文解码、字符串分割的所有报错都会被直接跳过,无法定位具体哪一步执行失败。
  • 正文匹配逻辑僵化:硬编码了两段固定文案做字符串分割,只要OTP邮件的文案、排版有细微变动(比如多空格、换行、措辞修改),分割操作就会返回长度不足的列表,触发分割后的索引错误,且错误被吞掉。
  • 邮件覆盖不全:仅处理了multipart类型的邮件,纯文本非多部分格式的邮件会被直接跳过,同时只固定取最新1封邮件,若最新邮件不是目标OTP邮件就会提取失败。
  • 等待逻辑不可靠:固定休眠10秒等待邮件送达,若网络延迟导致邮件投递慢,10秒时邮件还未入库就会查不到。
  • 输入框定位写法有隐患:XPath拼接时用str([i + 1])生成索引,属于错误写法,虽然凑巧能生成带方括号的索引,但兼容性极差。

修复后代码

import imaplib
import email
import time
import re

def get_otp(max_wait=30, check_interval=2):
    otp_pattern = re.compile(r'\b(\d{4,6})\b') # 匹配4-6位独立数字,适配绝大多数OTP格式
    imap = imaplib.IMAP4_SSL("imapmail.libero.it", 993)
    imap.login(username, password)
    print('邮箱登录成功')
    
    # 选中Social标签文件夹,替换原来的Inbox
    status, messages = imap.select("Social")
    if status != "OK":
        # 如果选文件夹失败,打印所有可用文件夹方便排查
        print("文件夹选中失败,可用文件夹列表:", imap.list())
        imap.logout()
        return []
    
    start_time = time.time()
    target_otp = None

    # 轮询查邮件,直到超过最大等待时间
    while time.time() - start_time < max_wait:
        status, messages = imap.search(None, 'ALL')
        if status != "OK":
            time.sleep(check_interval)
            continue
        
        mail_ids = messages[0].split()
        if not mail_ids:
            time.sleep(check_interval)
            continue
        
        # 取最新3封邮件检查,避免漏过
        check_ids = mail_ids[-3:] if len(mail_ids)>=3 else mail_ids
        for mail_id in reversed(check_ids):
            res, msg_data = imap.fetch(mail_id, "(RFC822)")
            for response in msg_data:
                if not isinstance(response, tuple):
                    continue
                msg = email.message_from_bytes(response[1])
                body = ""
                # 同时处理多部分和单部分邮件
                if msg.is_multipart():
                    for part in msg.walk():
                        content_type = part.get_content_type()
                        content_disposition = str(part.get("Content-Disposition"))
                        if content_type == "text/plain" and "attachment" not in content_disposition:
                            try:
                                body += part.get_payload(decode=True).decode(errors="ignore")
                            except Exception as e:
                                print(f"正文解码失败: {e}")
                else:
                    try:
                        body = msg.get_payload(decode=True).decode(errors="ignore")
                    except Exception as e:
                        print(f"正文解码失败: {e}")
                
                # 用正则提取OTP,不依赖固定文案
                match = otp_pattern.search(body)
                if match:
                    target_otp = match.group(1)
                    # 找到4位OTP就直接返回,适配当前4位验证码场景
                    if len(target_otp) ==4:
                        imap.close()
                        imap.logout()
                        return [int(target_otp)]
        
        time.sleep(check_interval)
    
    imap.close()
    imap.logout()
    print(f"等待{max_wait}秒未找到OTP邮件")
    return []

# 直接调用轮询逻辑,不需要额外固定sleep
otp = get_otp()
if not otp:
    raise Exception("未获取到有效OTP")
otp_split = list(str(otp[0]))

# 填充4位验证码,修正XPath拼接逻辑
for i in range(4):
    otp_elem = browser.find_element_by_xpath(f'//*[@id="loginForm"]/div[1]/div/div[1]/input[{i + 1}]')
    otp_elem.send_keys(otp_split[i])

otp_login_elem = browser.find_element_by_xpath('XPath of submit button')
otp_login_elem.click()

额外排查点

如果替换代码后还是选不到Social文件夹,可以先执行print(imap.list())打印出Libero账号下所有可用的IMAP文件夹名称,替换成对应Social标签的真实文件夹名即可。

内容的提问来源于stack exchange,提问作者user19044453

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 03:54:22