如何在python中读取eml文件? [英] How to read eml file in python?

查看:381
本文介绍了如何在python中读取eml文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不知道如何在python 3.4中加载eml文件.
我想列出所有内容并在python中阅读所有内容.

I do not known how to load a eml file in python 3.4.
I want to list all and read all of them in python.

推荐答案

这是您获取电子邮件内容的方式,即* .eml文件. 这在Python2.5-2.7上完美运行.在3上尝试一下.它应该也可以正常工作.

This is how you get content of an e-mail i.e. *.eml file. This works perfectly on Python2.5 - 2.7. Try it on 3. It should work as well.



from email import message_from_file
import os

# Path to directory where attachments will be stored:
path = "./msgfiles"

# To have attachments extracted into memory, change behaviour of 2 following functions:

def file_exists (f):
    """Checks whether extracted file was extracted before."""
    return os.path.exists(os.path.join(path, f))

def save_file (fn, cont):
    """Saves cont to a file fn"""
    file = open(os.path.join(path, fn), "wb")
    file.write(cont)
    file.close()

def construct_name (id, fn):
    """Constructs a file name out of messages ID and packed file name"""
    id = id.split(".")
    id = id[0]+id[1]
    return id+"."+fn

def disqo (s):
    """Removes double or single quotations."""
    s = s.strip()
    if s.startswith("'") and s.endswith("'"): return s[1:-1]
    if s.startswith('"') and s.endswith('"'): return s[1:-1]
    return s

def disgra (s):
    """Removes < and > from HTML-like tag or e-mail address or e-mail ID."""
    s = s.strip()
    if s.startswith("<") and s.endswith(">"): return s[1:-1]
    return s

def pullout (m, key):
    """Extracts content from an e-mail message.
    This works for multipart and nested multipart messages too.
    m   -- email.Message() or mailbox.Message()
    key -- Initial message ID (some string)
    Returns tuple(Text, Html, Files, Parts)
    Text  -- All text from all parts.
    Html  -- All HTMLs from all parts
    Files -- Dictionary mapping extracted file to message ID it belongs to.
    Parts -- Number of parts in original message.
    """
    Html = ""
    Text = ""
    Files = {}
    Parts = 0
    if not m.is_multipart():
        if m.get_filename(): # It's an attachment
            fn = m.get_filename()
            cfn = construct_name(key, fn)
            Files[fn] = (cfn, None)
            if file_exists(cfn): return Text, Html, Files, 1
            save_file(cfn, m.get_payload(decode=True))
            return Text, Html, Files, 1
        # Not an attachment!
        # See where this belongs. Text, Html or some other data:
        cp = m.get_content_type()
        if cp=="text/plain": Text += m.get_payload(decode=True)
        elif cp=="text/html": Html += m.get_payload(decode=True)
        else:
            # Something else!
            # Extract a message ID and a file name if there is one:
            # This is some packed file and name is contained in content-type header
            # instead of content-disposition header explicitly
            cp = m.get("content-type")
            try: id = disgra(m.get("content-id"))
            except: id = None
            # Find file name:
            o = cp.find("name=")
            if o==-1: return Text, Html, Files, 1
            ox = cp.find(";", o)
            if ox==-1: ox = None
            o += 5; fn = cp[o:ox]
            fn = disqo(fn)
            cfn = construct_name(key, fn)
            Files[fn] = (cfn, id)
            if file_exists(cfn): return Text, Html, Files, 1
            save_file(cfn, m.get_payload(decode=True))
        return Text, Html, Files, 1
    # This IS a multipart message.
    # So, we iterate over it and call pullout() recursively for each part.
    y = 0
    while 1:
        # If we cannot get the payload, it means we hit the end:
        try:
            pl = m.get_payload(y)
        except: break
        # pl is a new Message object which goes back to pullout
        t, h, f, p = pullout(pl, key)
        Text += t; Html += h; Files.update(f); Parts += p
        y += 1
    return Text, Html, Files, Parts

def extract (msgfile, key):
    """Extracts all data from e-mail, including From, To, etc., and returns it as a dictionary.
    msgfile -- A file-like readable object
    key     -- Some ID string for that particular Message. Can be a file name or anything.
    Returns dict()
    Keys: from, to, subject, date, text, html, parts[, files]
    Key files will be present only when message contained binary files.
    For more see __doc__ for pullout() and caption() functions.
    """
    m = message_from_file(msgfile)
    From, To, Subject, Date = caption(m)
    Text, Html, Files, Parts = pullout(m, key)
    Text = Text.strip(); Html = Html.strip()
    msg = {"subject": Subject, "from": From, "to": To, "date": Date,
        "text": Text, "html": Html, "parts": Parts}
    if Files: msg["files"] = Files
    return msg

def caption (origin):
    """Extracts: To, From, Subject and Date from email.Message() or mailbox.Message()
    origin -- Message() object
    Returns tuple(From, To, Subject, Date)
    If message doesn't contain one/more of them, the empty strings will be returned.
    """
    Date = ""
    if origin.has_key("date"): Date = origin["date"].strip()
    From = ""
    if origin.has_key("from"): From = origin["from"].strip()
    To = ""
    if origin.has_key("to"): To = origin["to"].strip()
    Subject = ""
    if origin.has_key("subject"): Subject = origin["subject"].strip()
    return From, To, Subject, Date

# Usage:
f = open("message.eml", "rb")
print extract(f, f.name)
f.close()

我使用邮箱为我的邮件组进行了编程,这就是为什么它如此复杂的原因. 它从未使我失败.从来没有任何垃圾.如果消息是多部分的,则输出字典将包含一个 键文件"(一个下标),其中包含非文本或html提取的其他文件的所有文件名. 那是一种提取附件和其他二进制数据的方法. 您可以在pullout()中对其进行更改,也可以仅更改file_exists()和save_file()的行为.

I programmed this for my mailgroup using mailbox, that is why it is so convoluted. It never failed me. Never any junk. If message is multipart, output dictionary will contain a key "files" (a sub dict) with all filenames of extracted other files that were not text or html. That was a way of extracting attachments and other binary data. You may change it in pullout(), or just change the behaviour of file_exists() and save_file().

construct_name()根据消息ID和多部分消息构造一个文件名 文件名(如果有的话).

construct_name() constructs a filename out of message id and multipart message filename, if there is one.

在pullout()中,Text和Html变量是字符串.对于在线邮件组,可以将不是一次性附件的任何文本或HTML打包成多部分.

In pullout() the Text and Html variables are strings. For online mailgroup it was OK to get any text or HTML packed into multipart that wasn't an attachment at once.

如果您需要更复杂的内容,请将文本"和"HTML"更改为列表,然后追加到列表中,并根据需要添加它们. 没问题.

If you need something more sophisticated change Text and Html to lists and append to them and add them as needed. Nothing problematic.

这里可能有一些错误,因为它旨在与mailbox.Message()一起使用, 不与email.Message()一起使用.我在email.Message()上试过了,效果很好.

Maybe there are some errors here, because it is intended to work with mailbox.Message(), not with email.Message(). I tried it on email.Message() and it worked fine.

您说过,您希望列出所有内容".从哪里?如果您引用的是POP3邮箱或一些不错的开源邮件程序的邮箱,则可以使用邮箱模块来完成此操作. 如果您想从其他人中列出它们,那么您将遇到问题. 例如,要从MS Outlook获取邮件,您必须知道如何读取OLE2复合文件. 其他邮件程序很少将它们称为* .eml文件,因此我认为这正是您想要做的. 然后在PyPI上搜索olefile或compoundfiles模块,然后在Google上搜索如何从MS Outlook收件箱文件中提取电子邮件. 或者将自己弄得一团糟,然后将它们从那里导出到某个目录.当您将它们作为eml文件时,请应用此代码.

You said, you "wish to list them all". From where? If you refer to the POP3 mailbox or a mailbox of some nice open-source mailer, then you do it using mailbox module. If you want to list them from others, then you have a problem. For example, to get mails from MS Outlook, you have to know how to read OLE2 compound files. Other mailers rarely refer to them as *.eml files, so I think this is exactly what you would like to do. Then search on PyPI for olefile or compoundfiles module and Google around for how to extract an e-mail from MS Outlook inbox file. Or save yourself a mess and just export them from there to some directory. When you have them as eml files, then apply this code.

这篇关于如何在python中读取eml文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆