Как мне ответить на электронное письмо с помощью Python imaplib и добавить оригинальное сообщение? - PullRequest
16 голосов
/ 02 февраля 2010

В настоящее время я использую imaplib для получения сообщений электронной почты с сервера и обработки содержимого и вложений.

Я хотел бы ответить на сообщения с сообщением о состоянии / ошибке и ссылками на полученный сгенерированный контент на моем сайте, если они могут быть обработаны. Это должно включать исходное сообщение, но должно отбрасывать любые вложения (которые будут большими) и предпочтительно заменять их только их именами файлов / размерами.

Поскольку я уже прохожу части сообщения MIME, я предполагаю, что мне нужно создать новое дерево сообщений MIME, содержащее копию исходного сообщения, и удалить / заменить узлы вложения.

Прежде чем я пошел по этому пути, я надеялся, что кто-нибудь может дать мне несколько советов. Есть ли какая-либо функция библиотеки для этого? Любое стандартное поведение я должен придерживаться?

В настоящее время я знаю, что / я использую модули imaplib, smtplib и email, но, возможно, что-то там упустил. Это работает и в Django, поэтому можно использовать что-нибудь в django.core.email, если это облегчает задачу.

1 Ответ

16 голосов
/ 03 февраля 2010

Исходная древовидная структура MIME входящего сообщения выглядит следующим образом (с использованием email.iterators._structure(msg)):

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

Ответ через GMail приводит к следующей структуре:

multipart/alternative
    text/plain
    text/html

Ieони не так умны, как я думал, просто отбрасывают вложения (хорошо) и предоставляют текстовые и HTML-версии, которые явно реструктурируют «цитируемый контент».

Я начинаю думать, что это все, что я должен делатьтакже, просто ответьте простым сообщением, так как после отбрасывания вложений нет особого смысла сохранять исходное сообщение.

Тем не менее, с тем же успехом можно было бы ответить и на мой первоначальный вопрос, поскольку я все равно понял, как это сделать сейчас.

Сначала замените все вложения в исходном сообщении на текстовые / обычные заполнители:

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()

Результатt заканчивается (по крайней мере, в GMail), показывая исходное сообщение как "---- Forwarded message ----", что не совсем то, что я хотел, но общая идея работает, и я надеюсь, что этот ответ поможет кому-то попытаться выяснитькак возиться с сообщениями MIME.

...