How can I send HTML emails with embedded images? How the HTML should link to the images? The images should be added as MultiPart email attach?
Any example is very appreciated.
How can I send HTML emails with embedded images? How the HTML should link to the images? The images should be added as MultiPart email attach?
Any example is very appreciated.
I achieved what op is asking for using django's mailing system. Upsides it that it'll use django settings for mailing (including a different subsystem for testing, etc. I also use mailhogs during development). It's also quite a bit higher level:
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
message = EmailMultiAlternatives(
subject=subject,
body=body_text,
from_email=settings.DEFAULT_FROM_EMAIL,
to=recipients,
**kwargs
)
message.mixed_subtype = 'related'
message.attach_alternative(body_html, "text/html")
message.attach(logo_data())
message.send(fail_silently=False)
logo_data is a helper function that attaches the logo (the image I wanted to attach in this case):
from email.mime.image import MIMEImage
from django.contrib.staticfiles import finders
from functools import lru_cache
@lru_cache()
def logo_data():
with open(finders.find('emails/logo.png'), 'rb') as f:
logo_data = f.read()
logo = MIMEImage(logo_data)
logo.add_header('Content-ID', '<logo>')
return logo
If you want to send email with image as attachment (in my situation it was image that has been caught directly from form, after its saving) you can use the following code as example:
#forms.py
from django import forms
from django.core.mail import EmailMessage
from email.mime.image import MIMEImage
class MyForm(forms.Form):
#...
def save(self, *args, **kwargs):
# In next line we save all data from form as usual.
super(MyForm, self).save(*args, **kwargs)
#...
# Your additional post_save login can be here.
#...
# In my case name of field was an "image".
image = self.cleaned_data.get('image', None)
# Then we create an "EmailMessage" object as usual.
msg = EmailMessage(
'Hello',
'Body goes here',
'from@example.com',
['to1@example.com', 'to2@example.com'],
['bcc@example.com'],
reply_to=['another@example.com'],
headers={'Message-ID': 'foo'},
)
# Then set "html" as default content subtype.
msg.content_subtype = "html"
# If there is an image, let's attach it to message.
if image:
mime_image = MIMEImage(image.read())
mime_image.add_header('Content-ID', '<image>')
msg.attach(mime_image)
# Then we send message.
msg.send()
I have tried the below code and it worked.
Code:
msg = EmailMessage()
# generic email headers
msg['Subject'] = 'Welcome'
msg['From'] = 'abc@gmail.com'
recipients = ['abc@gmail.com']
# set the plain text body
msg.set_content('This is a plain text body.')
# now create a Content-ID for the image
image_cid = make_msgid(domain='')
# if `domain` argument isn't provided, it will
# use your computer's name
# set an alternative html body
msg.add_alternative("""\
<html>
<body>
<table border='0' cellpadding='1' cellspacing='0' width='800'>
<tbody>
<tr>
<td height='506'>
<table border='0' cellpadding='0' cellspacing='0' width='600'>
<tbody>
<tr>
<td valign='top'>
<img height='190' src="cid:{image_cid}" width='800' tabindex='0'>
</td>
</tr>
<tr>
<td height='306' valign='top'>
<table cellpadding='0' cellspacing='20' width='800'>
<tbody>
<tr>
<td align='left' height='804' style='font-family:arial,helvetica,sans-serif;font-size:13px' valign='top'>
Hi {name},<br><br>
Welcome!
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
""".format(image_cid=image_cid[1:-1],name='ABC'), subtype='html')
# image_cid looks like <long.random.number@xyz.com>
# to use it as the img src, we don't need `<` or `>`
# so we use [1:-1] to strip them off
# now open the image and attach it to the email
with open('/path/image.jpg', 'rb') as img:
# know the Content-Type of the image
maintype, subtype = mimetypes.guess_type(img.name)[0].split('/')
# attach it
msg.get_payload()[1].add_related(img.read(),
maintype=maintype,
subtype=subtype,
cid=image_cid)
server = smtplib.SMTP(host=<hostname>, port=25)
server.starttls()
# send the message via the server.
server.sendmail(msg['From'], recipients, msg.as_string())
server.quit()