0

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 =['me@me.com']
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'] = 'test@test.com'
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('test@test.com', mail_to, msg.as_string())
server.close()
DapperDuck
  • 2,728
  • 1
  • 9
  • 21
AlexW
  • 2,843
  • 12
  • 74
  • 156

2 Answers2

1

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 =['me@me.com']
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'] = 'test@test.com'
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('test@test.com', mail_to, msg.as_string())
server.close()
Chandan
  • 11,465
  • 1
  • 6
  • 25
0

You may find it easier to embed the images with base64 encoding

import base64
# read image file to bytes
with open("alexw.png", "br") as fh:
    content = fh.read()
# base64 the image bytes, then convert to a UTF-8 string
b64_img_str = base64.b64encode(content).decode("utf-8") 

# prepare a string ready to embed in the email
img_src = f"""<img src="data:image/png;base64, {b64_img_str} alt="foo"</img>"""

<img src="data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAA7EAAAOxAGVKw4bAAADnklEQVRYha2XQWgcVRjHf5tddhCy0VJppEIsWlyQbt1l91BF0ICgl1zMKbkkOWSjlyxFb4rMRZGqyNZLNgWz8ZBcmoPNQUTpUgzoQpJdukVNbWObg6EFU0z2koGwHuJ7ffPmvZ3dtP/T+883833f+97/+2Ymcv6nj1qVrRVsqE1U5Hru+gLDySH6nITkE2dHffZdr0khl7f6E9jYuUWpNk/PVHos9Gbh/OLapVBebixSXJ21+rm5c5v3r37MyHeTVLZWiCWPn2Zw4DXaVaHT4ALlxiKArxJ/7mxSqs9z9e7PtGjJ61HXdd1TTw5weWPZGNyJxn3OAUr1+bZ2gPr9G+wfeBx/4hif/VrkQvVrNv+9G7gvBqBWYTo76XO46zV9D+xpfDg5xHBy6LASjUX2vCbT2Ulp73MSfD7oAnD5jyt88stXwQQAptJjVLZWpKhEEqKMoqzT2UkS8V7JVUGKa4l4b0CIpuAAPWIhqgAwcXbUt4tCLs94asTKTRpQhWgL7quAqIKA2l4iqInrwdUkAJ7tfcYaHCDSarWkJE19bnLeDfQ5os+JmGq8uHbpoaAeQ3AVuj+RRI/JaAs+nhrxaaNTezuNRJ9750W3XZ+rzgu5PJn+FE40TnV7vSN72JyIhfW5QF+8V64TyjrMHjYnot/PLrv7Bx71+zcAmHnrC5mhiur2Ok40zu0HfxlVbbMXcnmcmMPCb0uU6vP8/s9NAF4feBUn5jzsguLqLOXGItdGr9DnJCR/VNQmKkZNiSOLuq7rApw7mWX/wDs8w5gjuV6JbhGqAX2n6lqc3aNg12v6ZkFxddY3BwIaUIN/+Mp5Y0d0A7HTcyezALz3wwc+3gPB2S6CRyIRn7OjzgH93aByOQlFWfa8pjW4WjqbqGx2XdCCBzQAsPT/x4mqgaPOARX6jNnzmp1r4KhzwOZPHrM+B3zGSITM3KBxN91A96fyjjXwOIKbeCT9zRst28OiM2wTcTg5FPj80vtc/3e49WCT08eel1x+kpmCF3L5QIvqO2vXYnDYDXPXFyQv1b/1+TEmoLdU2JzoJonq32vU7jWkzfdNaAquJgF2jdj6XE1CoFQrM/P2l+YEljaWWdpYJtOfYio9xo93rnU0J0Ry7bhIorq9Tu1eg0x/KngELzx1iguDLsU3P+Wlp5OhGuiU6yjVyoBSgfSJM0xlxuVLQoX+cxLWWrZ3iQpRhdjLJ87wriWwKQldA0cJLjBTK/Mfsj51WkS2ihgAAAAASUVORK5CYII="
    alt="AlexW.png" />

See also base64 encoded images in email signatures

ti7
  • 16,375
  • 6
  • 40
  • 68