繁体   English   中英

在 Python 中从 IMAP 库读取电子邮件时如何处理所有字符集和内容类型

[英]How to handle all charset and content type when reading email from IMAP lib in Python

我正在从正在工作的 python 中的 imap lib 读取电子邮件,但我正在读取正文部分并将正文部分存储在数据库中,但有时 python 代码在解码正文中返回错误,我正在识别正文的内容类型和字符集,但不明白如何处理所有内容类型和字符集都有时间出现 text/plain ,某些邮件中的 utf-8 是 ascii/ISO-8859/window-1252。

请帮助我如何处理所有字符集。

找到我目前用于阅读电子邮件正文的以下代码,仅在需要时我将提供我的所有代码。

预期结果:以 UTF-8 格式转换/处理电子邮件正文的所有字符集,然后以 HTML 格式显示在门户上。

 if email_message.is_multipart():
    html = None
    multipart = True
    for part in email_message.walk():
        print("%s, %s" % (part.get_content_type(), part.get_content_charset()))
        charset = part.get_content_charset()
        if part.get_content_charset() is None:
            # We cannot know the character set, so return decoded "something"
            text = part.get_payload(decode=True)
            continue
        if part.get_content_type() == 'text/plain' and part.get_content_charset() == 'utf-8':
            # print('text--->1')
            text = str(part.get_payload(decode=True))
            # text = html.decode("utf-8")
            # print(part.get_payload(decode=True))
        if part.get_content_type() == 'text/plain' and part.get_content_charset() != 'utf-8':
            # print('text--->2')
            html = part.get_payload(decode=True)
            # text1 = html.decode("utf-8")
            text1 = html.decode(part.get_content_charset()).encode('utf8')
        if part.get_content_type() == 'text/html' and part.get_content_charset() != 'windows-1252':
            html = part.get_payload(decode=True)
            # text1 = html.decode("utf-8")
            text1 = html.decode(part.get_content_charset()).encode('utf8')
        if part.get_content_type() == 'text/html' and part.get_content_charset() == 'windows-1252':
            html = part.get_payload(decode=True)
            text1 = html.decode("cp1252")
        # if part.get_content_type() == 'text/html' and part.get_content_charset() == 'windows-1252':
        #    html = part.get_payload(decode=True)
        #    text1 = html.decode("latin-1")
        # if text is not None:
        # print(text.strip())
        # prin('Rahul')
        # else:
    # print("text")    #    print( html.strip())
    # print(text1.strip())
    # print("text1")
    # print(text1)
    imageCount = 0
    imageKey = ''
    json_data = {}
    filedata = {}
    mydict1 = ''
    value = ''
    params = ''
    filename = ''
    newFileName = ''
    for part in email_message.walk():
        if part.get_content_maintype() == 'multipart':
            continue
        if part.get('Content-Disposition') is None:
            continue
        if part.get_content_type() == 'message/rfc822':
            part_string = (bytes(str(part), 'utf-8'))
            # part_string = bytes(str(part.get_payload(0)),'utf-8')
            print('EML Part')
            print(part_string)
            filename = part.get_filename()
            # filename = filename.replace('\r', '').replace('\n', '')
            # print(part_string)
            # print(('attachment wala'))
        else:
            part_string = part.get_payload(decode=True)
            # print(part_string)
            # print(('attachment wala'))
            filename = part.get_filename()
            # filename = filename.replace('\r', '').replace('\n', '')
        if filename is not None:
            filepart = []
            try:
                decodefile = email.header.decode_header(filename)
                print('decodefile')
                print(decodefile)
            except HeaderParseError:
                return filename
                #
            for line1, encoding1 in decodefile:
                enc = 'utf-8'
                #        print(encoding)
                if encoding1 is not None:  # else encoding
                    print(type(line1))
                    filepart.append((line1.decode(encoding1)))
                    print('line')
                    print(line1)
                    print(filepart)
                    filename = ''.join(filepart)[:1023]
                else:
                    filename = filename
            dot_position = filename.rfind('.')
            file_prefix = filename[0: dot_position]
            file_suffix = filename[dot_position: len(filename)]
            print(filename)
            print(file_prefix)
            print(file_suffix)
            # filename = filename.decode('utf-8')
            # subject = ''
            file_prefix = file_prefix.replace('/', '_')
            now = datetime.datetime.now()
            timestamp = str(now.strftime("%Y%m%d%H%M%S%f"))
            print('timestamp--->')
            print(timestamp)
            newFileName = file_prefix + "_" + timestamp + file_suffix
            newFileName = newFileName.replace('\r', '').replace('\n', '').replace(',', '')
            filename = filename.replace('\r', '').replace('\n', '').replace(',', '')
            sv_path = os.path.join(svdir, newFileName)
            mydict = filename + '$$' + newFileName
            mydict1 = mydict1 + ',' + mydict
            # print(mydict1)
            value, params = cgi.parse_header(part.get('Content-Disposition'))
            print(value)
            if value == 'inline':
                imageCount = imageCount + 1
                print("newFileName-->" + newFileName)
                filedata[imageCount] = newFileName
                print(filedata)
                json_data = (filedata)
            # inlineImages = inlineImages + ',' + newFileName + '{{' + str(imageCount) + '}}'
            # print(json_data)
            # print('TYPE-->')
            # print(type(raw_email))
            # print(type(part.get_payload(decode=1)))
            # if type(part.get_payload(decode=1)) is None:
            #    print('message Type')
            if not os.path.isfile(sv_path):
                # print('rahul1')
                try:
                    fp = open(sv_path, 'wb')
                    fp.write(part_string)
                    fp.close()
                except TypeError:
                    pass
                    fp.close()

else:
    print("%s, %s" % (email_message.get_content_type(), email_message.get_content_charset()))
    if email_message.get_content_charset() is None:
        # We cannot know the character set, so return decoded "something"
        text = email_message.get_payload(decode=True)
        continue
    if email_message.get_content_type() == 'text/plain' and email_message.get_content_charset() == 'utf-8':
        print('text--->1')
        text = str(email_message.get_payload(decode=True))
        # text = html.decode("utf-8")
        # print(part.get_payload(decode=True))
    if email_message.get_content_type() == 'text/plain' and email_message.get_content_charset() != 'utf-8':
        print('text--->2')
        html = email_message.get_payload(decode=True)
        # text1 = html.decode("utf-8")
        text1 = html.decode(email_message.get_content_charset()).encode('utf8')
    if email_message.get_content_type() == 'text/html' and email_message.get_content_charset() != 'windows-1252':
        html = email_message.get_payload(decode=True)
        # text1 = html.decode("utf-8")
        text1 = html.decode(email_message.get_content_charset()).encode('utf8')
    if email_message.get_content_type() == 'text/html' and email_message.get_content_charset() == 'windows-1252':
        html = email_message.get_payload(decode=True)
        text1 = html.decode("cp1252")

在 Python 中从 IMAP 库读取电子邮件时如何处理所有字符集和内容类型

简单回答:
遍历所有消息部分并应用提供的编码设置。 我看到你已经这样做了(尽管我会将你的 if-else 级联重写为更简单的东西,因为 stdlib impl 可以很好地处理它,你的代码目前有点混乱)。 这将适用于标准符合邮件内容。 但与往常一样 - 有许多搞砸了的邮件客户端不太关心标准一致性(从在某些情况下损坏的好客户端到弱脚本垃圾邮件客户端)。

长答案:
不可能对所有消息都做到这一点。 由于各种原因,解码将失败。 每当部分解码失败时,问题是 - 该怎么办? 那么你基本上有这些选择:

  1. 没有什么特别的,只用原始内容
    您可以将原始字节内容插入到您的数据库中,并将该内容提供给用户。 这对用户来说不是很友好,如果您拥有庞大的用户群并伴随着业务限制,那么这可能不是您想要的。 它仍然是处理损坏内容的更简单的方法。 如果 2. 仍然失败,它也是后备。

  2. 尝试使用一些启发式方法解码内容
    讨厌的编码从这里开始 - 每当部分解码失败时,注释编码和实际内容就会出现问题。 那么你可以在这里做什么? 好吧,除了检查内容,尝试寻找实际编码的提示(如 UTF8 位掩码的模式匹配),甚至是蛮力解码。 聪明的启发式方法可能想先尝试经常出现的编码错误(例如,测试 UTF8 或 8 位编码,如较早的 latin-1)。 这里不存在一个好的经验法则,因为混乱的文本编码可以从错误宣布的编码类型到混合的几个 8 位编码。 虽然第一个最有可能被发现,但后者即使通过最先进的启发式算法也永远无法解决,并且应该始终退回到 1 中的解决方案。

  3. 跳过内容
    不推荐,因为它可能会隐瞒用户的重要数据。 只有在您确定内容是垃圾时才这样做。

如果您想采用启发式方法,我建议您执行以下操作:

  • 从标准符合处理开始,任何遵循标准的消息都应该被正确处理(在一个完美的世界里,你在这里完成了)
  • 实施 1. 以上作为一般故障转移
  • 从自己的用户那里收集有关典型故障的数据,或者在互联网上搜索典型故障(其他邮件客户端已经识别出这些并以某种方式处理它们)
  • 在 2. 中实现启发式,遵循 80/20 规则(首先实现大多数用户会从中受益的东西),其他一切都由 1 处理。
  • 随着时间的推移改进启发式
  • 在任何情况下 - 尽量避免 3。

这是对您的问题的非常笼统的回答,如果您有特定问题,也许您应该更详细地解决这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM