15

在我的 Web 应用程序中,我偶尔会使用这样的可重用邮件应用程序发送电子邮件:

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 编码邮件模板的简单方法,当我发送它们时会正确呈现?

4

2 回答 2

34

更新

非常感谢Saqib Ali在我回复近 5 年后再次提出这个老问题。

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

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

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

...在文档中稍晚一些...

默认情况下,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)附加到替代部分。然后将图像附加到相关的根。

于 2009-10-27T20:34:55.987 回答
2

我在使用 Jarret 在 Django 1.10 上的配方时遇到了麻烦——因为您可以附加 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)
于 2016-12-30T21:49:51.950 回答