создание шаблона электронной почты MIME с изображениями для отправки с помощью Python/Django
Вопрос
В своем веб-приложении я время от времени отправляю электронные письма, используя повторно используемое почтовое приложение, например:
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 со встроенными изображениями, которые будут корректно отображаться при отправке?
Решение
Обновлять
Большое спасибо Сакиб Али за возрождение этого старого вопроса почти через 5 лет после моего ответа.
Инструкции, которые я дал тогда, больше не работают.Я подозреваю, что за прошедшие годы в Django произошли некоторые улучшения, а это означает, что send_mail()
обеспечивает использование простого текста.Независимо от того, что вы вкладываете в контент, он всегда будет доставлен в виде обычного текста.
Самый последний Документация Джанго объясняет, что send_mail()
на самом деле это просто удобство для создания экземпляра django.core.mail.EmailMessage
класс, а затем вызываю send()
на этом экземпляре. EmailMessage
есть примечание к параметру body, которое объясняет результаты, которые мы видим сейчас в 2014 году:
тело:Основной текст.Это должно быть обычное текстовое сообщение.
...несколько позже в документации...
По умолчанию тип MIME параметра body в сообщении EmailMessage — «text/plain».Хорошей практикой является оставить это в покое.
Достаточно справедливо (признаюсь, я не нашел времени выяснить, почему инструкции 2009 года работали — я тестировал их еще в 2009 году — или когда они изменились).Django предоставляет, и документ, а django.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 в качестве корневого.Затем создайте еще одну часть MIMEMultipart с подтипом «альтернативный» и прикрепите к альтернативной части MIMEText (подтип html) и MIMEText (простой подтип).Затем прикрепите изображение к соответствующему корню.
Другие советы
У меня были проблемы с рецептом Джаррета на Django 1.10 - он получал MIME и ошибки кодирования для различных способов прикрепления данных MIME.
Вот простой многокомпонентный транзакционный шаблон для электронного письма со встроенным файловым объектом coupon_image
, который работает в 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)