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

IMAPLIB无法识别XML格式.xls后缀邮件附件的问题求解

用户问题

使用imaplib处理邮件时所有功能运行正常,仅当附件为XML格式电子表格且后缀为.XLS时,现有代码无法识别该类附件,相关代码如下:

for self.i in tqdm(range(latest_email_id, oldest_email_id - 1, -1)):
        print("Incrementation:",self.i)
        #x = mail[i-1]
        status = ""
        xdeleted = False
        typ, x = self.m.fetch(str(self.i), '(RFC822)')
        raw_email = x[0][1]
        raw_email_string = raw_email.decode()
        email_message = email.message_from_string(raw_email_string)

        for response_part in x:
            if isinstance(response_part, tuple):
                msg = email.message_from_string(response_part[1].decode())
        #print(x.senton.date())
        #sentondate = pd.to_datetime(x.senton.date())

        senderemail = msg['from']
        subject = msg['subject'].replace("\n","").replace("\r","")
        datemsg = msg["Date"]
        subject, encoding = email.header.decode_header(subject)[0]
        if (encoding == None):
            subject = subject
        else:
            subject = subject.decode(encoding)

        print("subject:", subject)
        print("Date:", datemsg)
        attachmentsfilenamesconcat = ""
        attachments = []
        for part in email_message.walk():
            if part.get_content_maintype() == 'multipart':
                continue
            if part.get('Content-Disposition') is None:
                continue
            fileName, encoding = decode_header(str(part.get_filename()))[0]
            if (encoding is None):
                fileName = fileName.replace("\r","").replace("\n","")
            else:
                fileName = fileName.decode(encoding).replace("\r","").replace("\n","")

            attachments.append(fileName)
            if bool(fileName):
                fnwoext, file_extension = os.path.splitext(os.path.join(self.DIR_ATT, fileName))
                if ((file_extension.lower() == ".csv") | (file_extension.lower() == ".xls") | (
                        file_extension.lower() == ".xlsx") \
                        | (file_extension.lower() == ".xlsm") | (file_extension.lower() == ".pdf") | (
                                file_extension.lower() == ".zip") \
                        | (file_extension.lower() == ".txt")):
                    print(os.path.join(self.DIR_ATT, fileName))

                    filePath = os.path.join(self.DIR_ATT,fileName)
                    fp = open(filePath, 'wb')
                    fp.write(part.get_payload(decode = True))
                    fp.close()

请问需要调整哪部分语法逻辑,才能正常检测到这类附件?


问题原因

你遇到的识别失败是因为XML格式的.XLS文件(即XML Spreadsheet 2003格式)通常存在邮件头异常问题,现有逻辑有两处过滤规则会漏掉这类附件:

  1. 部分邮件客户端发送这类文件时,不会在Content-Disposition头中标记为attachment,会被你代码中if part.get('Content-Disposition') is None: continue直接过滤
  2. 部分场景下这类文件的文件名存储在Content-Type的name参数中,part.get_filename()在部分Python版本中无法读取该参数,导致拿到空文件名被过滤
  3. 代码存在冗余的两次邮件对象解析逻辑,解析头部用的msg和遍历附件用的email_message是独立的两个对象,极端场景下会出现内容不一致
修改方案

需要调整两处核心逻辑:

1. 删掉冗余的邮件解析代码,统一使用同一个邮件对象

把原来重复解析msg的逻辑删掉,所有头部信息直接从email_message中读取:

typ, x = self.m.fetch(str(self.i), '(RFC822)')
raw_email = x[0][1]
raw_email_string = raw_email.decode()
email_message = email.message_from_string(raw_email_string)
# 删掉下面冗余的解析逻辑
# for response_part in x:
#     if isinstance(response_part, tuple):
#         msg = email.message_from_string(response_part[1].decode())

# 后面头部读取统一用email_message
senderemail = email_message['from']
subject = email_message['subject'].replace("\n","").replace("\r","")
datemsg = email_message["Date"]

2. 调整附件读取逻辑,兼容异常头信息的附件

把附件遍历部分的代码调整为如下内容:

for part in email_message.walk():
    if part.get_content_maintype() == 'multipart':
        continue
    # 优先读Content-Disposition的filename,读不到则尝试读Content-Type的name参数
    fileName = part.get_filename()
    if not fileName:
        content_type = part.get('Content-Type', '')
        if 'name=' in content_type:
            fileName = content_type.split('name=')[1].strip('"\' ')
    # 无明确文件名的才跳过,不再以Content-Disposition是否存在作为过滤条件
    if not fileName:
        continue
    # 解码文件名,不要提前转str避免把None转为字符串"None"
    fileName, encoding = decode_header(fileName)[0]
    if encoding:
        fileName = fileName.decode(encoding)
    fileName = fileName.replace("\r","").replace("\n","").strip()

    attachments.append(fileName)
    fnwoext, file_extension = os.path.splitext(fileName)
    # 原后缀判断逻辑保留即可,转小写后.XLS会自动匹配到.xls规则
    if file_extension.lower() in [".csv", ".xls", ".xlsx", ".xlsm", ".pdf", ".zip", ".txt"]:
        filePath = os.path.join(self.DIR_ATT, fileName)
        with open(filePath, 'wb') as fp:
            fp.write(part.get_payload(decode = True))

调整完成后即可正常识别这类后缀为.XLS的XML格式电子表格附件。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 02:54:02