Python - 电子邮件头解码UTF-8

Han*_*ser 34 python email email-headers

是否有任何Python模块有助于解码各种形式的编码邮件标题,主要是主题,简单 - 比如说 - UTF-8字符串?

以下是我拥有的邮件文件的示例主题标题:

Subject: [ 201105311136 ]=?UTF-8?B?IMKnIDE2NSBBYnM=?=. 1 AO;
Subject: [ 201105161048 ] GewSt:=?UTF-8?B?IFdlZ2ZhbGwgZGVyIFZvcmzDpHVmaWdrZWl0?=
Subject: [ 201105191633 ]
  =?UTF-8?B?IERyZWltb25hdHNmcmlzdCBmw7xyIFZlcnBmbGVndW5nc21laHJhdWZ3ZW5kdW4=?=
  =?UTF-8?B?Z2VuIGVpbmVzIFNlZW1hbm5z?=
Run Code Online (Sandbox Code Playgroud)

文本 - 编码的刺痛 - 文本

文本 - 编码的字符串

text - 编码的字符串 - 编码的字符串

Encodig也可能是ISO 8859-15之类的东西.

更新1:我忘了提,我试过了email.header.decode_header

    for item in message.items():
    if item[0] == 'Subject':
            sub = email.header.decode_header(item[1])
            logging.debug( 'Subject is %s' %  sub )
Run Code Online (Sandbox Code Playgroud)

这输出

DEBUG:root:Subject是[('[201101251025] ELStAM; =?UTF-8?B?IFZlcmbDvGd1bmcgdm9tIDIx?=.Januar 2011',无)]

这没有什么帮助.

更新2:感谢Ingmar Hupp的评论.

第一个示例解码为两个tupels的列表:

print decode_header("""[201105161048] GewSt:=?UTF-8?B?IFdlZ2ZhbGwgZGVyIFZvcmzDpHVmaWdrZWl0?=""")
[('[201105161048] GewSt:',None),('Wegfall der Vorl\xc3\xa4ufigkeit', 'UTF-8')]

这总是[(字符串,编码),(字符串,编码),...]所以我需要一个循环将所有[0]项连接到一个字符串或如何在一个字符串中得到它?

主题:[201101251025] ELStAM; =?UTF-8?B?IFZlcmbDvGd1bmcgdm9tIDIx?=.Januar 2011

解码不好:

print decode_header("""[201101251025] ELStAM; =?UTF-8?B?IFZlcmbDvGd1bmcgdm9tIDIx?=.Januar 2011""")

[('[201101251025] ELStAM; =?UTF-8?B?IFZlcmbDvGd1bmcgdm9tIDIx?=.Januar 2011',无)]

Ing*_*upp 48

这种类型的编码称为MIME编码字,电子邮件模块可以对其进行解码:

from email.header import decode_header
print decode_header("""=?UTF-8?B?IERyZWltb25hdHNmcmlzdCBmw7xyIFZlcnBmbGVndW5nc21laHJhdWZ3ZW5kdW4=?=""")
Run Code Online (Sandbox Code Playgroud)

这将输出元组列表,其中包含已解码的字符串和使用的编码.这是因为格式支持单个标头中的不同编码.要将它们合并为单个字符串,您需要将它们转换为共享编码,然后将其连接起来,这可以使用Python的unicode对象来完成:

from email.header import decode_header
dh = decode_header("""[ 201105161048 ] GewSt:=?UTF-8?B?IFdlZ2ZhbGwgZGVyIFZvcmzDpHVmaWdrZWl0?=""")
default_charset = 'ASCII'
print ''.join([ unicode(t[0], t[1] or default_charset) for t in dh ])
Run Code Online (Sandbox Code Playgroud)

更新2:

此主题行无法解码的问题:

Subject: [ 201101251025 ] ELStAM;=?UTF-8?B?IFZlcmbDvGd1bmcgdm9tIDIx?=. Januar 2011
                                                                     ^
Run Code Online (Sandbox Code Playgroud)

实际上是发送者的错误,它违反了标题中由空格分隔的编码字的要求,在RFC 2047第5节第1段中规定:"编码字"出现在标题字段中,定义为'*text'必须通过'linear-white-space'与任何相邻的'encoded-word'或'text'分开.

如果需要,你可以通过使用在编码字部分之后插入空格的正则表达式预处理这些损坏的标题来解决这个问题(除非它在最后),如下所示:

import re
header_value = re.sub(r"(=\?.*\?=)(?!$)", r"\1 ", header_value)
Run Code Online (Sandbox Code Playgroud)

  • @guettli:在Python 3上, [`str(make_header(decode_header(subject)))`](http://stackoverflow.com/a/21715870/4279) 适用于问题中的所有示例(不需要`re. sub`、`''.join`)(这是 3 次调用,而不是 1 次,但也没有那么糟糕)。 (2认同)

San*_*ann 40

我只是在Python 3.3中使用编码头进行测试,我发现这是一种非常方便的方法来处理它们:

>>> from email.header import Header, decode_header, make_header

>>> subject = '[ 201105161048 ] GewSt:=?UTF-8?B?IFdlZ2ZhbGwgZGVyIFZvcmzDpHVmaWdrZWl0?='
>>> h = make_header(decode_header(subject))
>>> str(h)
'[ 201105161048 ] GewSt:  Wegfall der Vorläufigkeit'
Run Code Online (Sandbox Code Playgroud)

如您所见,它会自动在编码的单词周围添加空格.

它在内部保持编码和ASCII标题部分分开,正如您在重新编码非ASCII部分时所看到的那样:

>>> h.encode()
'[ 201105161048 ] GewSt: =?utf-8?q?_Wegfall_der_Vorl=C3=A4ufigkeit?='
Run Code Online (Sandbox Code Playgroud)

如果您希望重新编码整个标头,可以将标头转换为字符串,然后再转换为标头:

>>> h2 = Header(str(h))
>>> str(h2)
'[ 201105161048 ] GewSt:  Wegfall der Vorläufigkeit'
>>> h2.encode()
'=?utf-8?q?=5B_201105161048_=5D_GewSt=3A__Wegfall_der_Vorl=C3=A4ufigkeit?='
Run Code Online (Sandbox Code Playgroud)

  • 这种技术似乎也适用于Python 2.7,但使用`unicode()`而不是`str()`将头对象转换回(unicode)字符串. (6认同)
  • 这是正确的答案,[`email.header`](https://docs.python.org/3.3/library/email.header.html)中的文档没有说明这一点,但是`make_header(decode_header( ))`是如何正确解码电子邮件标题. (4认同)

小智 7

def decode_header(value):
    return ' '.join((item[0].decode(item[1] or 'utf-8').encode('utf-8') for item in email.header.decode_header(value)))
Run Code Online (Sandbox Code Playgroud)


小智 5

如何通过以下方式解码标头:

import poplib, email

from email.header import decode_header, make_header

...

        subject, encoding = decode_header(message.get('subject'))[0]

        if encoding==None:
            print "\n%s (%s)\n"%(subject, encoding)
        else:
            print "\n%s (%s)\n"%(subject.decode(encoding), encoding)
Run Code Online (Sandbox Code Playgroud)

这从电子邮件中获取主题并使用指定的编码对其进行解码(如果编码设置为“无”则不进行解码)。

为我工作,编码设置为“None”、“utf-8”、“koi8-r”、“cp1251”、“windows-1251”


acr*_*ron -1

Python 有一个电子邮件库。 http://docs.python.org/library/email.header.html

看看 email.header.decode_header()