创建一个MIME电子邮件模板,其中包含要使用python / django发送的图像

时间:2009-10-27 19:26:10

标签: python django email mime

在我的网络应用程序中,我偶尔使用可重复使用的邮件程序应用程序发送电子邮件:

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" )

我想发送一封包含嵌入图片的电子邮件,所以我尝试在邮件客户端制作邮件,查看源代码,并将其放入我的模板(welcome.eml),但我一直无法获得它在发送时在邮件客户端中正确呈现。

有没有人知道我使用内嵌图像创建mime编码邮件模板的简单方法,这些模板在发送时会正确呈现?

2 个答案:

答案 0 :(得分:27)

<强>更新

非常感谢Saqib Ali在我回复近5年后重新提出这个旧问题。

我当时给出的指示不再有效。我怀疑Django在这几年中有一些改进,这意味着send_mail()强制执行纯文本。无论您在内容中添加什么内容,它都将以纯文本形式发送。

最新Django documentation解释了send_mail()实际上只是为了创建django.core.mail.EmailMessage类的实例,然后在该实例上调用send()EmailMessage有一个关于body参数的注释,它解释了我们现在在2014年看到的结果:

  

body:正文。这应该是纯文本消息。

     

...稍后在文档中......

     

默认情况下,EmailMessage中body参数的MIME类型为“text / plain”。保持这一点是一种好习惯。

足够公平(我承认我没有花时间调查为什么2009年的指示有效 - 我在2009年测试过它们 - 或者当它发生变化时)。 Django确实提供了documentdjango.core.mail.EmailMultiAlternatives类,以便更容易发送同一消息的纯文本和HTML表示。

这个问题的案例略有不同。我们不是要寻求替代本身的替代方案,而是将相关的部分附加到其中一个替代方案中。在HTML版本中(如果你有或省略了纯文本版本并不重要),我们想要嵌入一个图像数据部分。不是内容的替代视图,而是HTML正文中引用的相关内容。

仍然可以发送嵌入的图像,但我没有看到使用send_mail执行此操作的简单方法。现在是时候省去便利功能并直接实例化EmailMessage

以下是对上一个示例的更新:

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()

2009年的原始回复:

要发送包含嵌入图像的电子邮件,请使用python的内置电子邮件模块来构建MIME部分。

以下应该这样做:

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")

实际上,您可能希望将HTML与纯文本替换一起发送。在这种情况下,使用MIMEMultipart创建“相关”mimetype容器作为根。然后使用子类型“alternative”创建另一个MIMEMultipart,并将MIMEText(子类型html)和MIMEText(子类型plain)附加到替代部件。然后将图像附加到相关的根目录。

答案 1 :(得分:2)

我在Django 1.10上使用Jarret的配方遇到了麻烦 - 因为你可以通过各种方式附加MIME数据而获得MIME和编码错误。

这是一个简单的多部分事务模板,用于包含可在django 1.10上运行的嵌入式coupon_image文件对象的电子邮件:

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)