15 Ago 2016, una pieza de 14 minutos por Dev Mukherjee
La mayoría de los servicios de Internet necesitan enviar correos electrónicos a sus usuarios. La construcción del mensaje es una tarea independiente al envío del correo electrónico. Este post demuestra la construcción adecuada de los mensajes MIME (Multipurpose Internet Mail Extensions) en Python.
Los mensajes MIME tienen muchos subtipos para encapsular diferentes tipos de contenido. La biblioteca MIME de correo electrónico de Python proporciona envolturas para trabajar con ellos. Exploraremos los siguientes subtipos para demostrar cómo empaquetar los mensajes adecuadamente:
-
mixed
utilizado para enviar contenido de diferentes tipos, en línea o como archivos adjuntos -
alternative
utilizado para enviar versiones alternativas del mismo contenido, por ejemplo, agrupar versiones de texto plano y HTML de un cuerpo de correo electrónico -
related
utilizado para incluir recursos relacionados en línea o como archivos adjuntos, por ejemplo imágenes utilizadas en su contenido HTML
El mensaje de correo electrónico que crearemos en este post contendrá:
- Versiones HTML y de texto plano del contenido del cuerpo
- Un archivo adjunto (que en este caso es un archivo
ICS
generado) - Opcionalmente tendrá una imagen en el contenido HTML
Comencemos por crear un mensaje MIME multiparte mixed
que albergará los distintos componentes (cuerpo del correo electrónico, imágenes mostradas en línea y archivos adjuntos descargables) de nuestro mensaje:
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]>"
Contenido del cuerpo en texto plano y HTML
Crearemos un mensaje alternative
que contenga dos archivos adjuntos, el primero con la versión en texto plano del mensaje de correo electrónico, seguido de la versión HTML.
El contenido HTML y de texto se produciría normalmente con la ayuda de un motor de plantillas. Para los propósitos de este post asumo que ya has generado el contenido y está disponible como una variable str
de Python.
El mensaje alternative
se crea instanciando un objeto MIMEMultipart
, esta vez pidiendo al constructor que utilice el subtipo alternative
.
textual_message = MIMEMultipart('alternative')
Usa el ayudante MIMEText
para crear el texto plano y los adjuntos 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)
Agrega el mensaje alternative
al mensaje padre mixed
para crear el cuerpo textual del mensaje de correo electrónico.
# Attach this to the mixed type messagemessage.attach(textual_message)
Adjuntos descargables
Se pueden adjuntar archivos textuales o binarios al correo electrónico utilizando el helper MIMEApplication
. Se instala con el contenido del archivo adjunto seguido del tipo MIME del archivo adjunto, es decir, para un application/pdf
se suministra la parte pdf
.
Por defecto, el contenido estaría en línea. Para convertirlo en un adjunto, utilice el método add_header
en la instancia MIMEApplication
y declare que es un adjunto. Dado que el contenido del adjunto es ahora parte de un mensaje codificado, debe proporcionar explícitamente meta información como un nombre de archivo.
from email.mime.application import MIMEApplicationpdf_file = MIMEApplication(pdf_file_data, "pdf")pdf_file.add_header('Content-Disposition', 'attachment', filename='report.pdf')
El ayudante MIMEApplication
codifica automáticamente Base64
los contenidos cuando se adjuntan a los mensajes:
message.attach(pdf_file)
Imagen opcional para utilizar en el cuerpo HTML
Considere una imagen que desee mostrar en el cuerpo del correo electrónico pero que no quiera ofrecer al destinatario para su descarga. Tendrías que utilizar un mensaje related
para envolver el cuerpo del correo electrónico contenido en el mensaje alternate
que creamos anteriormente y adjuntar el mensaje related
al mensaje original mixed
.
También necesitarás el uso de la subclase MIMEImage
para asegurarte de que la imagen se codifica correctamente. Lo primero es crear un mensaje MIMEMultipart
de subtipo related
:
related_message = MIMEMultipart('related')
Crea una instancia de MIMEImage
que contenga el contenido de la imagen:
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>')
Añadir una cabecera Content-ID
te permitirá referenciar la imagen en el contenido HTML como <img src="cid:image1">
. Adjunte el mensaje alternate
creado originalmente al mensaje related
seguido de la instancia MIMEImage
:
# Attach the alternative textural message to the # related messagerelated_message.attach(textual_message)# Attach the image to the related messagerelated_message.attach(image)
Finalmente adjunte el mensaje related
al mensaje mixed
:
# Attach the related message to our parent messagemessage.attach(related_message)
Codificación y envío del correo electrónico
Una vez mezclados y combinados varios tipos y subtipos de MIME
, su mensaje puede ser codificado llamando a la función as_string
. Ésta, a su vez, pide a todos los submensajes y archivos adjuntos que se presenten como un mensaje coherente. El resultado es la cadena que puede enviar a través de SMTP
como su correo electrónico.
encoded_email = message.as_string()
smtplib
proporciona un cliente SMTP
que puede entregar este mensaje para usted. Es bastante sencillo. Dependiendo de la configuración de su aplicación y del servidor, puede optar por utilizar relés locales o retransmitir directamente a un servidor SMTP disponible. Dejaré eso a las necesidades específicas de sus aplicaciones.
from smtplib import SMTPsmtp = SMTP("localhost", 25)smtp.sendmail(message, message, encoded_email)smtp.quit()
Nota: La directiva Reply-To
no es parte de la carga útil SMTP; eso se maneja como parte del mensaje MIME
.