【问题标题】:Getting mail attachment to python file object获取邮件附件到 python 文件对象
【发布时间】:2011-05-03 08:21:27
【问题描述】:

我有一个电子邮件多部分消息对象,我想将该电子邮件消息中的附件转换为 python 文件对象。这可能吗?如果可能的话,我应该研究 Python 中的什么方法或类来完成这样的任务?

【问题讨论】:

  • 到目前为止,您阅读了 Python 库的哪一部分?你看过 pop 或 imap 库吗?
  • 我只查看了 email.message.Message 和 mimetools.Message。好的,我会读到 pop 和 imail,看看我能用它做什么。

标签: python email


【解决方案1】:

我不太明白您所说的“电子邮件多部分消息对象”是什么意思。您的意思是属于email.message.Message 类的对象吗?

如果这就是你的意思,那很简单。在多部分消息上,get_payload 方法返回消息部分的列表(每个部分本身都是一个 Message 对象)。您可以遍历这些部件并检查它们的属性:例如,get_content_type 方法返回部件的 MIME 类型,get_filename 方法返回部件的文件名(如果在消息中指定了任何文件名)。然后当你找到正确的消息部分后,你可以调用get_payload(decode=True)来获取解码后的内容。

>>> import email
>>> msg = email.message_from_file(open('message.txt'))
>>> len(msg.get_payload())
2
>>> attachment = msg.get_payload()[1]
>>> attachment.get_content_type()
'image/png'
>>> open('attachment.png', 'wb').write(attachment.get_payload(decode=True))

如果您以编程方式从收到的电子邮件中提取附件,您可能需要采取预防措施来防范病毒和特洛伊木马。特别是,您可能应该只提取您知道其 MIME 类型是安全的附件,并且您可能想要选择自己的文件名,或者至少清理 get_filename 的输出。

【讨论】:

  • HTML 邮件通常在页脚中有图像,这些图像也作为附件发送。您可以通过查看 Content-Disposition 将它们与“真实”附件区分开来:内联图像以“inline”开头,而实际附件以“attachment”开头。没有获取内容处置的方法,但如果您只对实际附件感兴趣,则可以调用 part.get('Content-Disposition').startswith('attachment')。
【解决方案2】:

这是可行的解决方案,消息来自 IMAP 服务器

self.imap.select()
typ, data = self.imap.uid('SEARCH', 'ALL')
msgs = data[0].split()
print "Found {0} msgs".format(len(msgs))

for uid in msgs:
    typ, s = self.imap.uid('FETCH', uid, '(RFC822)')
    mail = email.message_from_string(s[0][1])

    print "From: {0}, Subject: {1}, Date: {2}\n".format(mail["From"], mail["Subject"], mail["Date"])

    if mail.is_multipart():
        print 'multipart'
        for part in mail.walk():
            ctype = part.get_content_type()
            if ctype in ['image/jpeg', 'image/png']:
                open(part.get_filename(), 'wb').write(part.get_payload(decode=True))

【讨论】:

    【解决方案3】:

    实际上使用现在建议的email.EmailMessage API(不要与旧的email.Message API混淆)相当容易:

    1. 遍历所有邮件元素并仅选择附件

    2. 仅遍历附件

    假设您将消息作为字节内容存储在信封变量中

    解决方案 1:

    import email
    from email.message import EmailMessage
    
    email_message: EmailMessage = email.message_from_bytes(envelope, _class=EmailMessage)
    
    for email_message_part in email_message.walk():
        if email_message.is_attachment():
            # Do something with your attachment
    

    解决方案 2:(最好不要遍历消息对象的其他部分)

    import email
    from email.message import EmailMessage
    
    email_message: EmailMessage = email.message_from_bytes(envelope, _class=EmailMessage)
    
    for email_message_attachment in email_message.iter_attachments():
            # Do something with your attachment
    

    注意几点:

    1. 我们通过_class=EmailMessage 参数明确告诉在我们的字节读取方法中使用新的EmailMessage
    2. 借助message.Parser API 中的内置方法,您可以从类似字节的对象、二进制文件对象或字符串等来源读取电子邮件消息(又名信封)

    【讨论】:

      猜你喜欢
      • 2015-07-14
      • 1970-01-01
      • 2011-09-19
      • 1970-01-01
      • 2013-06-08
      • 1970-01-01
      • 2014-10-19
      • 2010-10-16
      • 2012-08-23
      相关资源
      最近更新 更多