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 alternativeque 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 Base64los 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.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.