• Pl chevron_right

      Python: send emails with embedded images

      pubsub.slavino.sk / planetdebian · Thursday, 4 November, 2021 - 13:45 · 1 minute

    to send emails with images you need to use MIMEMultipart , but the basic approach:

    import smtplib

    from email.mime.multipart import MIMEMultipart
    from email.mime.image import MIMEImage

    msg = MIMEMultipart('alternative')
    msg['Subject'] = "subject"
    msg['From'] = from_addr
    msg['To'] = to_addr

    part = MIMEImage(open('/path/to/image', 'rb').read())

    s = smtplib.SMTP('localhost')
    s.sendmail(from_addr, to_addr, msg.as_string())
    s.quit()

    will produce an email with empty body and the image as an attachment.

    The better way, ie to have the image as part of the body of the email, requires to write an HTML body that refers to that image:

    import smtplib

    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from email.mime.image import MIMEImage

    msg = MIMEMultipart('alternative')
    msg['Subject'] = "subject
    msg['From'] = from_addr
    msg['To'] = to_addr

    text = MIMEText('<img src="cid:image1">', 'html')
    msg.attach(text)

    image = MIMEImage(open('/path/to/image', 'rb').read())

    # Define the image's ID as referenced in the HTML body above
    image.add_header('Content-ID', '<image1>')
    msg.attach(image)

    s = smtplib.SMTP('localhost')
    s.sendmail(from_addr, to_addr, msg.as_string())
    s.quit()

    The trick is to define an image with a specific Content-ID and make that the only item in an HTML body: now you have an email with contains that specific image as the only content of the body, embedded in it.

    Bonus point : if you want to take a snapshot of a webpage (which is kinda the reason i needed the code above) i found it extremely useful to use the Google PageSpeed Insights API ; a good description on how to use that API with Python is available at this StackOverflow answer.

    UPDATE (2020-12-26): I was made aware via email that some mail providers may not display images inline when the Content-ID value is too short (say, for example, Content-ID: 1 ). A solution that seems to work on most of the providers is using a sequence of random chars prefixed with a dot and suffixed with a valid mail domain.

    Značky: #Debian