如何使用Python imaplib回复电子邮件并包含原始消息?

18

我目前正在使用imaplib从服务器获取电子邮件并处理其中的内容和附件。

如果可以处理这些消息,我想回复给对方一个状态/错误信息和链接到在我的网站上生成的内容。这应该包括原始消息,但应该删除任何附件(它们会很大),最好仅用文件名/大小替换它们。

由于我已经遍历了MIME消息的各个部分,我假设我需要做的就是构建一个新的MIME消息树,其中包含原始消息的副本,并删除/替换附件节点。

在我开始实现之前,我希望有人能给我一些提示。是否有任何库函数可以完成此操作?是否有任何标准行为应该遵循?

我目前知道/正在使用imaplibsmtplibemail模块,但可能已经错过了其中的一些明显的东西。这也在Django中运行,因此可以在django.core.email中使用任何内容,如果这样做可以更容易地解决问题。

1个回答

22

使用 email.iterators._structure(msg),传入的信息的原始 MIME 树结构如下:

multipart/mixed
    text/html                (message)
    application/octet-stream (attachment 1)
    application/octet-stream (attachment 2)

通过GMail回复的结果如下所示:

multipart/alternative
    text/plain
    text/html
即它们并不像我想象中那样聪明,只是丢弃附件(很好),并提供文本和HTML版本,显式地重新构造“引用内容”。
我开始认为这也是我应该做的全部,只需回复一条简单的消息,因为在丢弃附件之后,保留原始消息没有什么意义。
尽管如此,既然我已经知道了如何做,还是可以回答我的原始问题。
首先,在原始消息中用text/plain占位符替换所有附件:
import email

original = email.message_from_string( ... )

for part in original.walk():
    if (part.get('Content-Disposition')
        and part.get('Content-Disposition').startswith("attachment")):

        part.set_type("text/plain")
        part.set_payload("Attachment removed: %s (%s, %d bytes)"
                         %(part.get_filename(), 
                           part.get_content_type(), 
                           len(part.get_payload(decode=True))))
        del part["Content-Disposition"]
        del part["Content-Transfer-Encoding"]

然后创建一个回复消息:

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.message import MIMEMessage

new = MIMEMultipart("mixed")
body = MIMEMultipart("alternative")
body.attach( MIMEText("reply body text", "plain") )
body.attach( MIMEText("<html>reply body text</html>", "html") )
new.attach(body)

new["Message-ID"] = email.utils.make_msgid()
new["In-Reply-To"] = original["Message-ID"]
new["References"] = original["Message-ID"]
new["Subject"] = "Re: "+original["Subject"]
new["To"] = original["Reply-To"] or original["From"]
new["From"] = "me@mysite.com"

然后附上原始的 MIME 消息对象并发送:

new.attach( MIMEMessage(original) )

s = smtplib.SMTP()
s.sendmail("me@mysite.com", [new["To"]], new.as_string())
s.quit()

最终得到的结构如下:

multipart/mixed
    multipart/alternative
        text/plain
        text/html
    message/rfc822
        multipart/mixed
            text/html
            text/plain
            text/plain

或者使用 Django 更简单:

from django.core.mail import EmailMultiAlternatives
from email.mime.message import MIMEMessage

new = EmailMultiAlternatives("Re: "+original["Subject"],
                             "reply body text", 
                             "me@mysite.com", # from
                             [original["Reply-To"] or original["From"]], # to
                             headers = {'Reply-To': "me@mysite.com",
                                        "In-Reply-To": original["Message-ID"],
                                        "References": original["Message-ID"]})
new.attach_alternative("<html>reply body text</html>", "text/html")
new.attach( MIMEMessage(original) ) # attach original message
new.send()

在GMail中,该结果最终显示为"---- 转发邮件 ----",这并不完全符合我的需求,但是总体思路可行,我希望这个答案能够帮助那些试图处理MIME消息的人。


3
我希望这个答案能帮助那些试图弄清楚如何操作MIME消息的人。-- 这确实有用。谢谢Tom! - aniketd
你好! 我按照您所写的做了,但是出现了错误: SMTPDataError: (552, b'5.7.0 由于其内容存在潜在的安全问题,此消息已被阻止。请访问 https://support.google.com/mail/?p=BlockedMessage 以查看我们的消息内容和附件内容指南。n5sm277571lfd.52 - gsmtp') - Vasyl Kolomiets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接