电子邮件附件的编码错误

时间:2014-10-22 20:53:20

标签: python windows email encoding

我在Windows上运行了一个python 2.7脚本。它登录gmail,检查新的电子邮件和附件:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

file_types = ["pdf", "doc", "docx"] # download attachments with these extentions

login = "login"
passw = "password"

imap_server = "imap.gmail.com"
smtp_server = "smtp.gmail.com"
smtp_port = 587

from smtplib import SMTP
from email.parser import HeaderParser
from email.MIMEText import MIMEText
import sys
import imaplib
import getpass
import email
import datetime
import os
import time

if __name__ == "__main__":
    try:
        while True:
            session = imaplib.IMAP4_SSL(imap_server)
            try:
                rv, data = session.login(login, passw)
                print "Logged in: ", rv
            except imaplib.IMAP4.error:
                print "Login failed!"
                sys.exit(1)

            rv, mailboxes = session.list()
            rv, data = session.select(foldr)
            rv, data = session.search(None, "(UNSEEN)")
            for num in data[ 0 ].split():
                rv, data = session.fetch(num, "(RFC822)")
                for rpart in data:
                    if isinstance(rpart, tuple):
                        msg = email.message_from_string(rpart[ 1 ])
                        to = email.utils.parseaddr(msg[ "From" ])[ 1 ]
                text = data[ 0 ][ 1 ]
                msg = email.message_from_string(text)
                got = []
                for part in msg.walk():
                    if part.get_content_maintype() == 'multipart':
                        continue
                    if part.get('Content-Disposition') is None:
                        continue
                    filename = part.get_filename()
                    print "file: ", filename
                    print "Extention: ", filename.split(".")[ -1 ]
                    if filename.split(".")[ -1 ] not in file_types:
                        continue
                    data = part.get_payload(decode = True)
                    if not data:
                        continue
                    date = datetime.datetime.now().strftime("%Y-%m-%d")
                    if not os.path.isdir("CONTENT"):
                        os.mkdir("CONTENT")
                    if not os.path.isdir("CONTENT/" + date):
                        os.mkdir("CONTENT/" + date)
                    ftime = datetime.datetime.now().strftime("%H-%M-%S")
                    new_file = "CONTENT/" + date + "/" + ftime + "_" + filename
                    f = open(new_file, 'wb')
                    print "Got new file %s from %s" % (new_file, to)
                    got.append(filename.encode("utf-8"))
                    f.write(data)
                    f.close()
            session.close()
            session.logout()
            time.sleep(60)
    except:
        print "TARFUN!"

问题是最后一次打印读取垃圾:
=?UTF-8?B?0YfQsNGB0YLRjCAxINGC0LXQutGB0YIg0LzQtdGC0L7QtNC40YfQutC4LmRv?=
例如 所以后来检查不起作用。在linux上它工作得很好。 现在我尝试将d [e]代码文件名设为utf-8。但它没有做任何事情。提前谢谢。

1 个答案:

答案 0 :(得分:0)

如果你阅读了定义文件名字段的规范,RFC 2183,第2.3节,它说:

  

当前[RFC 2045]语法限制参数值(因此      Content-Disposition文件名)到US-ASCII。我们认识到伟大的      允许在文件名中允许任意字符集,但是      定义必要的内容超出了本文档的范围      机制。我们希望基本的[RFC 1521]'价值'      有一天会修改规范以允许使用非US-ASCII      字符,在这个时候应该使用相同的机制      Content-Disposition文件名参数。

有人建议使用RFC来处理这个问题。特别是,有人建议将文件名处理为encoded-word,由RFC 5987RFC 2047RFC 2231定义。简而言之,这意味着RFC 2047格式:

"=?" charset "?" encoding "?" encoded-text "?="

...或RFC 2231格式:

"=?" charset ["*" language] "?" encoded-text "?="

某些邮件代理已经在使用此功能,其他人则不知道如何处理它。 Python 2.x中的email包是那些不知道如何处理它的包。 (有可能是Python 3.x中的更高版本,或者它可能会在未来发生变化,但如果你想坚持使用2.x,这对你没有帮助。)所以,如果你想解析这个,你必须自己做。

在您的示例中,您有一个RFC 2047格式的文件名,其中包含charset UTF-8(可直接用作Python编码名称),编码B,这意味着Base-64,和内容0YfQsNGB0YLRjCAxINGC0LXQutGB0YIg0LzQtdGC0L7QtNC40YfQutC4LmRv。所以,你必须对它进行base-64解码,然后对其进行UTF-8解码,然后得到u'часть 1 текст методички.do'

如果你想更普遍地这样做,你将不得不编写代码,如果可能的话,尝试解释RFC 2231格式的每个文件名,否则,以RFC 2047格式,并执行适当的解码步骤。这段代码在StackOverflow答案中写得非常简单,但基本思路非常简单,如上所示,所以你应该能够自己编写代码。您可能还想搜索PyPI以获取现有实现。