获取python getaddresses()来解码编码字编码

时间:2010-11-11 18:25:15

标签: python email encoding mime

msg = \
"""To: =?ISO-8859-1?Q?Caren_K=F8lter?= <ck@example.dk>, bob@example.com
Cc: "James =?ISO-8859-1?Q?K=F8lter?=" <jk@example.dk>
Subject: hello

message body blah blah blah

"""

import email.parser, email.utils
import itertools


parser = email.parser.Parser()
parsed_message = parser.parsestr(msg)

address_fields = ('to', 'cc')
addresses = itertools.chain(*(parsed_message.get_all(field) for field in address_fields if parsed_message.has_key(field)))
address_list = set(email.utils.getaddresses(addresses))


print address_list

似乎email.utils.getaddresses()似乎无法在地址字段中自动处理MIME RFC 2047

如何在下面获得预期结果?

实际结果:

set([('', 'bob@example.com'), ('=?ISO-8859-1?Q?Caren_K=F8lter?=', 'ck@example.dk'), ('James =?ISO-8859-1?Q?K=F8lter?=', 'jk@example.dk')])

期望的结果:

set([('', 'bob@example.com'), (u'Caren_K\xf8lter', 'ck@example.dk'), (u'James \xf8lter', 'jk@example.dk')])

3 个答案:

答案 0 :(得分:3)

您想要的功能是email.header.decode_header,它会返回(decoded_string, charset)对的列表。您可以根据charset对它们进行进一步解码,然后再将它们重新连接到email.utils.getaddresses或其他地方。

您可能认为这很简单:

def decode_rfc2047_header(h):
    return ' '.join(s.decode(charset or 'ascii')
                   for s, charset in email.header.decode_header(h))

但由于邮件标题通常来自不受信任的来源,因此您必须处理(1)编码错误的数据; (2)虚假字符集名称。所以你可能会这样做:

def decode_safely(s, charset='ascii'):
    """Return s decoded according to charset, but do so safely."""
    try:
        return s.decode(charset or 'ascii', 'replace')
    except LookupError: # bogus charset
        return s.decode('ascii', 'replace')

def decode_rfc2047_header(h):
    return ' '.join(decode_safely(s, charset)
                   for s, charset in email.header.decode_header(h))

答案 1 :(得分:1)

是的,email包界面在很多时候确实不是很有帮助。

在这里,您必须在每个地址上手动使用email.header.decode_header,然后,由于这会为您提供已解码的令牌列表,您必须再次手动将它们拼接在一起:

for name, address in email.utils.getaddresses(addresses):
    name= u' '.join(
        unicode(b, e or 'ascii') for b, e in email.header.decode_header(name)
    )
    ...

答案 2 :(得分:0)

谢谢Gareth Rees。您的回答有助于解决问题:

Input: 'application/octet-stream;\r\n\tname="=?utf-8?B?KFVTTXMpX0FSTE8uanBn?="'

编码词周围没有空格导致email.Header.decode_header忽略它。我太新了,不知道我是否只是让事情变得更糟,但这个kludge,加上''而不是'',修复了它:

if not ' =?' in h:
    h = h.replace('=?', ' =?').replace('?=', '?= ')

Output: u'application/octet-stream; name="(USMs)_ARLO.jpg"'