crear una plantilla de correo electrónico MIME con imágenes para enviar con python / django

StackOverflow https://stackoverflow.com/questions/1633109

  •  06-07-2019
  •  | 
  •  

Pregunta

En mi aplicación web, de vez en cuando envío correos electrónicos utilizando una aplicación de correo reutilizable como esta:

user - self.user
subject = ("My subject")
from = "me@mydomain.com"
message = render_to_string("welcomeEmail/welcome.eml", { 
                "user" : user,
                })
send_mail(subject, message, from, [email], priority="high" )

Deseo enviar un correo electrónico con imágenes incrustadas, así que intenté hacer el correo en un cliente de correo, ver la fuente y ponerlo en mi plantilla (welcome.eml), pero no pude obtener para que se procese correctamente en los clientes de correo cuando se envía.

¿Alguien sabe de una manera fácil para mí de crear plantillas de correo codificadas MIME con imágenes en línea que se muestren correctamente cuando las envíe?

¿Fue útil?

Solución

Actualizar

Muchas gracias a Saqib Ali por resucitar esta vieja pregunta casi 5 años después de mi respuesta.

Las instrucciones que di en ese momento ya no funcionan. Sospecho que ha habido algunas mejoras en Django en los años intermedios, lo que significa que send_mail () aplica texto sin formato. Independientemente de lo que incluya en el contenido, siempre se entregará como texto sin formato.

La documentación de Django más reciente explica que > send_mail () es realmente solo una conveniencia para crear una instancia de la clase django.core.mail.EmailMessage , y luego llamar a send () en ese ejemplo. EmailMessage tiene esta nota para el parámetro body, que explica los resultados que estamos viendo ahora en 2014:

  

cuerpo: el texto del cuerpo. Este debería ser un mensaje de texto sin formato.

     

... algo más tarde en los documentos ...

     

De manera predeterminada, el tipo MIME del parámetro body en un mensaje de correo electrónico es "text / plain". Es una buena práctica dejar esto solo.

Bastante justo (confieso que no me he tomado el tiempo para investigar por qué funcionaron las instrucciones de 2009, las probé en 2009 o cuando cambió). Django proporciona, y documento , un django.core.mail.EmailMultiAlternatives para facilitar el envío de un texto sin formato y una representación HTML del mismo mensaje.

El caso en esta pregunta es ligeramente diferente. No buscamos agregar una alternativa per se, sino agregar partes relacionadas a una de las alternativas. Dentro de la versión HTML (y no importa si tiene u omite la versión de texto plano), queremos incrustar una parte de datos de imagen. No es una vista alternativa del contenido, sino contenido relacionado al que se hace referencia en el cuerpo HTML.

Todavía es posible enviar una imagen incrustada, pero no veo una manera sencilla de hacerlo usando send_mail . Es hora de prescindir de la función de conveniencia e instanciar un EmailMessage directamente.

Aquí hay una actualización del ejemplo anterior:

from django.core.mail import EmailMessage
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# Load the image you want to send as bytes
img_data = open('logo.jpg', 'rb').read()

# Create a "related" message container that will hold the HTML 
# message and the image. These are "related" (not "alternative")
# because they are different, unique parts of the HTML message,
# not alternative (html vs. plain text) views of the same content.
html_part = MIMEMultipart(_subtype='related')

# Create the body with HTML. Note that the image, since it is inline, is 
# referenced with the URL cid:myimage... you should take care to make
# "myimage" unique
body = MIMEText('<p>Hello <img src="cid:myimage" /></p>', _subtype='html')
html_part.attach(body)

# Now create the MIME container for the image
img = MIMEImage(img_data, 'jpeg')
img.add_header('Content-Id', '<myimage>')  # angle brackets are important
img.add_header("Content-Disposition", "inline", filename="myimage") # David Hess recommended this edit
html_part.attach(img)

# Configure and send an EmailMessage
# Note we are passing None for the body (the 2nd parameter). You could pass plain text
# to create an alternative part for this message
msg = EmailMessage('Subject Line', None, 'foo@bar.com', ['bar@foo.com'])
msg.attach(html_part) # Attach the raw MIMEBase descendant. This is a public method on EmailMessage
msg.send()

Respuesta original de 2009:

Para enviar un correo electrónico con imágenes incrustadas, use el módulo de correo electrónico incorporado de python para construir las partes MIME.

Lo siguiente debería hacerlo:

from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# Load the image you want to send at bytes
img_data = open('logo.jpg', 'rb').read()

# Create a "related" message container that will hold the HTML 
# message and the image
msg = MIMEMultipart(_subtype='related')

# Create the body with HTML. Note that the image, since it is inline, is 
# referenced with the URL cid:myimage... you should take care to make
# "myimage" unique
body = MIMEText('<p>Hello <img src="cid:myimage" /></p>', _subtype='html')
msg.attach(body)

# Now create the MIME container for the image
img = MIMEImage(img_data, 'jpeg')
img.add_header('Content-Id', '<myimage>')  # angle brackets are important
msg.attach(img)

send_mail(subject, msg.as_string(), from, [to], priority="high")

En realidad, es probable que desee enviar el HTML junto con una alternativa de texto sin formato. En ese caso, use MIMEMultipart para crear el " relacionado " contenedor mimetype como la raíz. Luego cree otra MIMEMultipart con el subtipo "alternativa" y adjunte un MIMEText (subtipo html) y un MIMEText (subtipo simple) a la parte alternativa. Luego adjunte la imagen a la raíz relacionada.

Otros consejos

Estaba teniendo problemas con la receta de Jarret en Django 1.10: obtenía MIME y errores de codificación por las diversas formas en que puede adjuntar datos MIME.

Aquí hay una plantilla transaccional multiparte simple para un correo electrónico con un objeto de archivo coupon_image incrustado que funciona en django 1.10:

from django.core.mail import EmailMultiAlternatives
from email.mime.image import MIMEImage

def send_mail(coupon_image):
    params = {'foo':'bar'} # create a template context
    text_body = render_to_string('coupon_email.txt', params)
    html_body = render_to_string('coupon_email.html', params)
    img_data = coupon_image.read() #should be a file object, or ImageField
    img = MIMEImage(img_data)
    img.add_header('Content-ID', '<coupon_image>')
    img.add_header('Content-Disposition', 'inline', filename="coupon_image")

    email = EmailMultiAlternatives(
        subject="Here's your coupon!",
        body=text_body,
        from_email='noreply@example.com',
        to=['someone@example.com',]
    )

    email.attach_alternative(html_body, "text/html")
    email.mixed_subtype = 'related'
    email.attach(img)

    email.send(fail_silently=False)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top