2009-10-27 32 views
11

En mi aplicación web que envío mensajes de correo electrónico de vez en cuando usando una aplicación de correo reutilizable como esto:creación de una plantilla de correo electrónico MIME con imágenes para enviar con Python/Django

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

Quiero enviar un correo electrónico con imágenes incrustadas en ella , así que intenté hacer el correo en un cliente de correo, ver el código fuente y ponerlo en mi plantilla (welcome.eml), pero no pude hacerlo correctamente en los clientes de correo cuando se envió.

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

Respuesta

24

actualización

Muchas gracias a Saqib Ali para 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. No importa lo que coloque en el contenido, siempre se entregará como texto sin formato.

El más reciente Django documentation explica que send_mail() es en realidad sólo una conveniencia para la creación de una instancia de la clase django.core.mail.EmailMessage y, a continuación, llamar send() en esa instancia. EmailMessage tiene esta nota para el parámetro de cuerpo, que explica los resultados que estamos viendo ahora en 2014:

cuerpo: El cuerpo del texto. Esto debería ser un mensaje de texto sin formato.

... algo más tarde en la documentación ...

Por defecto, el tipo MIME del cuerpo en un parámetro EmailMessage es "text/plain". Es una buena práctica dejar esto en paz.

Bastante (confieso que no me he tomado el tiempo para investigar por qué funcionó las instrucciones de 2009 - las probé en 2009 - o cuando cambiaron). Django proporciona, y document, una clase django.core.mail.EmailMultiAlternatives para facilitar el envío de texto sin formato y 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 directa de hacerlo usando send_mail. Es hora de prescindir de la función de conveniencia y crear una instancia de EmailMessage directamente.

Aquí es una actualización para el 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, '[email protected]', ['[email protected]']) 
msg.attach(html_part) # Attach the raw MIMEBase descendant. This is a public method on EmailMessage 
msg.send() 

respuesta original a partir de 2009:

Para enviar un correo electrónico con imágenes incrustadas, el uso de Python integrado en el módulo de correo electrónico para construir las partes MIME.

Lo siguiente debe 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 contenedor mimetype "relacionado" como raíz. A continuación, cree otro MIMEMultipart con el subtipo "alternativa" y adjunte un MIMEText (subtipo html) y un MIMEText (subtipo normal) a la parte alternativa. Luego adjunte la imagen a la raíz relacionada.

+0

probé este código exacto y falló para mí: http://stackoverflow.com/ preguntas/21861593/how-can-i-send-inline-images-in-email-with-python-django –

+0

Muchas gracias Jarret !! Esto funcionó como un campeón! –

0

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

Aquí hay una plantilla de varias partes transaccional simple para un correo electrónico con un archivo incrustado coupon_image objeto 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='[email protected]', 
     to=['[email protected]',] 
    ) 

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

    email.send(fail_silently=False) 
Cuestiones relacionadas