15 août 2016, un morceau de 14 minutes par Dev Mukherjee
La plupart des services Internet ont besoin d’envoyer des emails à leurs utilisateurs. La construction du message est une tâche distincte de l’envoi de l’email. Ce post démontre la construction correcte des messages MIME (Multipurpose Internet Mail Extensions) en Python.
Les messages MIME ont de nombreux sous-types pour encapsuler différentes sortes de contenu. La bibliothèque MIME de messagerie de Python fournit des wrappers pour travailler avec eux. Nous allons explorer les sous-types suivants pour démontrer comment emballer les messages correctement :
-
mixed
utilisé pour envoyer du contenu de différents types, en ligne ou en tant que pièces jointes -
alternative
utilisé pour envoyer des versions alternatives du même contenu, par exemple grouper le texte brut et les versions HTML du corps d’un courriel -
related
utilisé pour inclure des ressources connexes en ligne ou en tant que pièces jointes, par ex. les images utilisées dans votre contenu HTML
Le message électronique que nous allons créer dans ce post contiendra :
- Des versions HTML et texte brut du contenu du corps
- Un fichier joint (qui dans ce cas est un fichier
ICS
généré) - Optionnellement avoir une image dans le contenu HTML
Commençons par créer un message MIME multipart mixed
qui abritera les différents composants (corps du courriel, images affichées en ligne et pièces jointes téléchargeables) de notre message :
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]>"
Contenu du corps en texte brut et en HTML
Nous allons créer un message alternative
qui comporte deux pièces jointes, la première contenant la version en texte brut du message électronique suivie de la version HTML.
Le contenu HTML et texte serait typiquement produit avec l’aide d’un moteur de templating. Pour les besoins de ce post, je suppose que vous avez déjà généré le contenu et qu’il est disponible en tant que variable Python str
.
Le message alternative
est créé en instanciant un objet MIMEMultipart
, cette fois en demandant au constructeur d’utiliser le sous-type alternative
.
textual_message = MIMEMultipart('alternative')
Utilisez l’aide MIMEText
pour créer les pièces jointes en texte brut et en HTML.
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)
Attachez le message alternative
au message parent mixed
pour créer le corps textuel du message électronique.
# Attach this to the mixed type messagemessage.attach(textual_message)
Pièce jointe téléchargeable
Des fichiers textuels ou binaires peuvent être joints à votre courriel en utilisant l’aide MIMEApplication
. Il est instancié avec le contenu de la pièce jointe suivi du type MIME de la pièce jointe c’est-à-dire que pour un application/pdf
vous lui fournissez la portion pdf
.
Par défaut le contenu serait contenu en ligne. Pour en faire une pièce jointe, utilisez la méthode add_header
sur l’instance MIMEApplication
et déclarez qu’elle est une pièce jointe. Comme le contenu de la pièce jointe fait maintenant partie d’un message codé, vous devez fournir explicitement des méta-informations comme un nom de fichier.
from email.mime.application import MIMEApplicationpdf_file = MIMEApplication(pdf_file_data, "pdf")pdf_file.add_header('Content-Disposition', 'attachment', filename='report.pdf')
L’aide MIMEApplication
encode automatiquement Base64
le contenu lorsqu’il est joint aux messages :
message.attach(pdf_file)
Image optionnelle à utiliser dans le corps HTML
Pensez à une image que vous voulez afficher dans le corps du courriel mais que vous ne voulez pas offrir au destinataire pour téléchargement. Vous auriez besoin d’utiliser un message related
pour envelopper le corps du courriel contenu dans le message alternate
que nous avons créé plus tôt et attacher le message related
au message mixed
original.
Vous aurez également besoin de l’utilisation de la sous-classe MIMEImage
pour vous assurer que l’image est encodée correctement. Tout d’abord, créez un message MIMEMultipart
de sous-type related
:
related_message = MIMEMultipart('related')
Créez une instance de MIMEImage
qui contiendra le contenu de l’image:
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>')
Ajouter un en-tête Content-ID
vous permettra de référencer l’image dans le contenu HTML en tant que <img src="cid:image1">
. Attachez le message alternate
créé initialement au message related
suivi de l’instance MIMEImage
:
# Attach the alternative textural message to the # related messagerelated_message.attach(textual_message)# Attach the image to the related messagerelated_message.attach(image)
Enfin, attachez le message related
au message mixed
:
# Attach the related message to our parent messagemessage.attach(related_message)
Encodage et envoi du courriel
Une fois que vous avez mélangé et assorti divers types et sous-types MIME
, votre message peut être encodé en appelant la fonction as_string
. Celle-ci, à son tour, demande à chaque sous-message et pièce jointe de se rendre en un seul message cohérent. Le résultat est la chaîne que vous pouvez envoyer sur SMTP
comme votre courriel.
encoded_email = message.as_string()
smtplib
fournit un client SMTP
qui peut délivrer ce message pour vous. C’est assez simple. Selon la configuration de votre application et de votre serveur, vous pouvez choisir d’utiliser des relais locaux ou de relayer directement vers un serveur SMTP disponible. Je laisserai cela aux besoins spécifiques de vos applications.
from smtplib import SMTPsmtp = SMTP("localhost", 25)smtp.sendmail(message, message, encoded_email)smtp.quit()
Note : La directive Reply-To
ne fait pas partie de la charge utile SMTP ; elle est traitée comme faisant partie du message MIME
.