Python 3 Embedded Images not attaching in email

My code embeds images into email, however it does not seem to be attaching. I’m receiving the mail but with the ? image icon. Everything I’ve searched and looked at suggests that they’re attached correctly.

Snippet of the mail template:

<body>
    <img src="cid:image_1"></img>
    {{ content }}
    <img src="cid:image_2"></img>
</body>

Mail function

template = 'Communications'
recipients =['[email protected]']
subject = 'Test Email'
text_data = 'PLAIN TEXT'
html_data = '<h2>HTML TEXT</h2>'

mail_template = MailTemplate.objects.filter(name=template).prefetch_related('mailimage_set').first()

# create jinja env for mail templates 
env = Environment(autoescape=False, optimized=False) 
plain_text_template = env.from_string(mail_template.plain_text_template)
html_template = env.from_string(mail_template.html_template)
# create templates and render content
plain_text_content = plain_text_template.render(content=text_data)
html_content = html_template.render(content=html_data)
# create message types
text = MIMEText(plain_text_content, 'plain')
html = MIMEText(html_content, 'html')
# create new mail
msg = MIMEMultipart('alternative')
msg.attach(text)
msg.attach(html)   

# set mail attribs
mail_to = ','.join(recipients)
msg['Subject'] = subject
msg['From'] = '[email protected]'
msg['To'] = mail_to
# add images
i = 1
for img in mail_template.mailimage_set.all():
    # open the image from s3 bucket
    img_data = urlopen(signed_url(img.image.url)).read()
    msgImage = MIMEImage(img_data)
    # Define the image's ID as referenced above
    msgImage.add_header('Content-ID', '<image_{}>'.format(i))
    # attach the image
    msg.attach(msgImage)
    # increase the image number
    i +=1

server = smtplib.SMTP('mxrelay.test.com', 25)
server.ehlo()
server.sendmail('[email protected]', mail_to, msg.as_string())
server.close()

Answer

Because Images are referenced inside Html they are related.

You can create another related MIMEMultipart, attach images mimetype and alternative MIMEMultipart to it and leave alternative as it is

template = 'Communications'
recipients =['[email protected]']
subject = 'Test Email'
text_data = 'PLAIN TEXT'
html_data = '<h2>HTML TEXT</h2>'

mail_template = MailTemplate.objects.filter(name=template).prefetch_related('mailimage_set').first()

# create jinja env for mail templates 
env = Environment(autoescape=False, optimized=False) 
plain_text_template = env.from_string(mail_template.plain_text_template)
html_template = env.from_string(mail_template.html_template)
# create templates and render content
plain_text_content = plain_text_template.render(content=text_data)
html_content = html_template.render(content=html_data)
# create message types
text = MIMEText(plain_text_content, 'plain')
html = MIMEText(html_content, 'html')
# create new mail
msg = MIMEMultipart('related')                   # related part for image
alt_msg = MIMEMultipart('alternative')
alt_msg.attach(text)
alt_msg.attach(html)
msg.attach(alt_msg)                              # attached alternative to related

# set mail attribs
mail_to = ','.join(recipients)
msg['Subject'] = subject
msg['From'] = '[email protected]'
msg['To'] = mail_to
# add images
i = 1
for img in mail_template.mailimage_set.all():
    # open image read bytes from url
    img_data = urlopen(signed_url(img.image.url)).read()
    img = MIMEImage(img_data)
    # define the image's ID as referenced above
    img.add_header('Content-ID', '<image_{}>'.format(i))
    # image would be displayed inline with content
    img.add_header("Content-Disposition", "inline", filename='<image_{}>'.format(i))
    # attach the image
    msg.attach(img)                              # attached image to related
    # increase the image number
    i +=1

server = smtplib.SMTP('mxrelay.test.com', 25)
server.ehlo()
server.sendmail('[email protected]', mail_to, msg.as_string())
server.close()