python - 在 Python 中从 IMAP lib 读取电子邮件时如何处理所有字符集和内容类型
问题描述
我正在从 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 lib 读取电子邮件时如何处理所有字符集和内容类型
简单的答案:
遍历所有消息部分并应用提供的编码设置。我看到您已经这样做了(尽管我会将您的 if-else 级联重写为更简单的东西,因为 stdlib impl 可以很好地处理它,但您的代码目前有点混乱)。这将适用于符合标准的邮件内容。但与往常一样 - 有许多搞砸的邮件客户端不太关心标准一致性(从在某些情况下损坏的好客户端到脚本弱的垃圾邮件客户端)。
长答案:
不可能对所有消息都正确。由于各种原因,解码将失败。每当部分解码失败时,问题是 - 该怎么办?好吧,您基本上有以下选择:
没有什么特别的,只使用原始内容
您可以将原始字节内容插入到您的数据库中,并为用户提供该内容。这对用户来说不是很友好,如果你有一个庞大的用户群并且业务约束与之耦合,那么这也不是你想要的。它仍然是处理损坏内容的更简单方法。如果 2. 仍然失败,它也是后备。尝试用一些启发式方法解码内容
这里开始讨厌的编码 - 每当部分解码失败时,注释编码和实际内容都有问题。那么你可以在这里做什么?好吧,除了检查内容之外,尝试找到实际编码的提示(例如 UTF8 位掩码的模式匹配),甚至是蛮力解码。聪明的启发式方法可能希望首先尝试常见的编码错误(例如,测试 UTF8 或 8 位编码,如之前的 latin-1)。这里不存在一个好的经验法则,因为混乱的文本编码可能从错误宣布的编码类型到混合在一起的几个 8 位编码。虽然最有可能发现第一个,但即使通过最先进的启发式算法也永远无法解决后者,并且应该始终回退到 1 中的解决方案。跳过内容
不推荐,因为它可能会向用户隐瞒重要数据。只有在您确定内容是垃圾的情况下才这样做。
如果您想采用启发式方法,我建议您执行以下操作:
- 从标准符合处理开始,任何遵循标准的消息都应该被正确处理(在一个完美的世界里,你在这里完成了)
- 实施 1. 以上作为一般故障转移
- 收集有关典型故障的数据,无论是从自己的用户那里还是在互联网上搜索典型故障(其他邮件客户端已经识别出这些并以某种方式处理它们)
- 实施 2. 中的启发式方法,遵循 80/20 规则(首先实施大多数用户将从中受益的东西),其他一切都由 1 处理。
- 随着时间的推移改进启发式
- 无论如何 - 尽量避免 3。
这是对您问题的一个非常笼统的答案,如果您有特定问题,也许您应该更详细地解决这个问题。
推荐阅读
- python - 使用同一个单词命名为 evaluate_plural 和 evaluate_singular 的函数是不好的做法吗?
- php - 引导轮播中的 mysqli_fetch_array() 错误
- c# - 通过 C# .NET 从 Excel 97-2003 电子表格中提取单个单元格或单元格范围
- c# - 绑定 ObservableCollection
字段到 ListBox DataTemplate - java - Weblogic 12.2.1.3.0 上的 Spring Boot Cloud Eureka
- python - 在 pyrorient OrientDb 中获取顶点或边记录?
- node.js - 如何在 RHEL 7.5 服务器上安装 NodeJS
- javascript - 元素不会消失使用 click() 方法来过渡元素不透明度
- ios - 易于实现日历吊舱?对象 c
- java - Spring Boot + Flyway + AWS:原因:java.sql.SQLException:找不到合适的驱动程序