15. August 2016, ein 14-minütiger Beitrag von Dev Mukherjee
Die meisten Internetdienste müssen E-Mails an ihre Benutzer senden. Das Erstellen der Nachricht ist eine andere Aufgabe als das Versenden der E-Mail. Dieser Beitrag demonstriert den korrekten Aufbau von MIME-Nachrichten (Multipurpose Internet Mail Extensions) in Python.
MIME-Nachrichten haben viele Untertypen, um verschiedene Arten von Inhalten zu kapseln. Die E-Mail-MIME-Bibliothek von Python bietet Wrapper für die Arbeit mit ihnen. Wir werden die folgenden Subtypen untersuchen, um zu demonstrieren, wie man Nachrichten richtig verpackt:
-
mixed
wird verwendet, um Inhalte verschiedener Typen inline oder als Anhänge zu versenden -
alternative
wird verwendet, um alternative Versionen desselben Inhalts zu versenden, z.B. um reine Text- und HTML-Versionen eines E-Mail-Bodys zu gruppieren -
related
wird verwendet, um verwandte Ressourcen inline oder als Anhänge einzubinden, z.B. Bilder, die in Ihrem HTML-Inhalt verwendet werden
Die E-Mail-Nachricht, die wir in diesem Beitrag erstellen werden, wird enthalten:
- HTML- und Klartextversionen des Hauptinhalts
- Eine angehängte Datei (in diesem Fall eine generierte
ICS
-Datei) - Optional ein Bild im HTML-Inhalt
Beginnen wir mit der Erstellung einer mixed
MIME-Multipart-Nachricht, die die verschiedenen Komponenten (Hauptteil der E-Mail, inline angezeigte Bilder und herunterladbare Anhänge) unserer Nachricht enthält:
from email.mime.multipart import MIMEMultipart# By default the type is set to mixedmessage = MIMEMultipart()message = "Hello World"message = "Anomaly Support <[email protected]>"message = "Anomaly Reception <[email protected]>"# If a Reply-To is explicitly provided then the email client will# use this address when the user hit the reply button message = "Anomaly Support <[email protected]>"
HTML und reiner Textkörper
Wir erstellen eine alternative
Nachricht mit zwei Anhängen, die zunächst die reine Textversion der E-Mail-Nachricht und dann die HTML-Version enthalten.
HTML- und Textinhalte werden normalerweise mit Hilfe einer Templating-Engine erstellt. Für die Zwecke dieses Beitrags gehe ich davon aus, dass Sie den Inhalt bereits erstellt haben und er als Python-Variable str
verfügbar ist.
Die alternative
-Nachricht wird durch Instanziierung eines MIMEMultipart
-Objekts erstellt, wobei der Konstruktor dieses Mal gebeten wird, den Subtyp alternative
zu verwenden.
textual_message = MIMEMultipart('alternative')
Verwenden Sie die MIMEText
-Hilfe, um den reinen Text und die HTML-Anhänge zu erstellen.
from email.mime.text import MIMEText# I assume that you have a variable called txt_content# with the textual rendition of the message, this could# have been generated via a templating engineplaintext_part = MIMEText(txt_content, 'plain')textual_message.attach(plaintext_part)# likewise a variable called html_content with the HTMLhtml_part = MIMEText(html_content, 'html')textual_message.attach(html_part)
Hängen Sie die alternative
Nachricht an die übergeordnete mixed
Nachricht an, um den Textkörper der E-Mail-Nachricht zu erstellen.
# Attach this to the mixed type messagemessage.attach(textual_message)
Herunterladbarer Anhang
Text- oder Binärdateien können mit dem MIMEApplication
Helper an Ihre E-Mail angehängt werden. Er wird mit dem Inhalt des Anhangs instanziiert, gefolgt vom MIME-Typ des Anhangs, d.h. für einen application/pdf
geben Sie den pdf
-Teil an.
Standardmäßig würde der Inhalt inline enthalten sein. Um dies zu einem Anhang zu machen, verwenden Sie die Methode add_header
für die Instanz MIMEApplication
und deklarieren sie als Anhang. Da der Inhalt des Anhangs nun Teil einer kodierten Nachricht ist, müssen Sie explizit Metainformationen wie einen Dateinamen angeben.
from email.mime.application import MIMEApplicationpdf_file = MIMEApplication(pdf_file_data, "pdf")pdf_file.add_header('Content-Disposition', 'attachment', filename='report.pdf')
Die MIMEApplication
-Hilfe kodiert den Inhalt automatisch Base64
, wenn er an Nachrichten angehängt wird:
message.attach(pdf_file)
Optionales Bild zur Verwendung im HTML-Textkörper
Denken Sie an ein Bild, das Sie im E-Mail-Textkörper anzeigen, dem Empfänger aber nicht zum Download anbieten wollen. Sie müssten eine related
-Nachricht verwenden, um den in der zuvor erstellten alternate
-Nachricht enthaltenen E-Mail-Text zu verpacken, und die related
-Nachricht an die ursprüngliche mixed
-Nachricht anhängen.
Sie müssen auch die Unterklasse MIMEImage
verwenden, um sicherzustellen, dass das Bild richtig kodiert wird. Erstellen Sie zunächst eine MIMEMultipart
-Nachricht des Untertyps related
:
related_message = MIMEMultipart('related')
Erstellen Sie eine Instanz von MIMEImage
, die den Bildinhalt enthält:
from email.MIMEImage import MIMEImage# Content of an image that relates to the HTML messageimage = MIMEImage(image_binary_contents)# Lets you reference the image locally in HTMLimage.add_header('Content-ID', '<image1>')
Durch Hinzufügen eines Content-ID
-Headers können Sie das Bild im HTML-Inhalt als <img src="cid:image1">
referenzieren. Hängen Sie die ursprünglich erstellte alternate
Nachricht an die related
Nachricht an, gefolgt von der MIMEImage
Instanz:
# Attach the alternative textural message to the # related messagerelated_message.attach(textual_message)# Attach the image to the related messagerelated_message.attach(image)
Hängen Sie schließlich die related
Nachricht an die mixed
Nachricht an:
# Attach the related message to our parent messagemessage.attach(related_message)
Kodierung und Versand der E-Mail
Nachdem Sie verschiedene MIME
Typen und Subtypen gemischt haben, kann Ihre Nachricht durch den Aufruf der Funktion as_string
kodiert werden. Diese wiederum fordert jede Teilnachricht und jeden Anhang auf, sich als eine zusammenhängende Nachricht darzustellen. Das Ergebnis ist die Zeichenkette, die Sie über SMTP
als E-Mail versenden können.
encoded_email = message.as_string()
smtplib
bietet einen SMTP
-Client, der diese Nachricht für Sie übermitteln kann. Es ist ziemlich einfach. Je nach Anwendung und Serverkonfiguration können Sie lokale Relays verwenden oder direkt an einen verfügbaren SMTP-Server weiterleiten. Ich überlasse das den spezifischen Anforderungen Ihrer Anwendung.
from smtplib import SMTPsmtp = SMTP("localhost", 25)smtp.sendmail(message, message, encoded_email)smtp.quit()
Anmerkung: Die Reply-To
-Direktive ist nicht Teil der SMTP-Nutzlast; sie wird als Teil der MIME
-Nachricht behandelt.