Python smtplib EmailMessage make_msgid renders elements and images incorrectly / wrong

35 Views Asked by At

I developing email-delivery (email-sending) for a company. This project is being developed for debt collection.

For project i use next stack and libraries:

  • python

  • smtlib

  • email

I designed html-template for email-message:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .logo-container {
            max-width: 620px;
            margin: 0 auto;
            border-top: 1px solid #e0e0e0;
            border-left: 1px solid #e0e0e0;
            border-right: 1px solid #e0e0e0;
            border-top-left-radius: 6px;
            border-top-right-radius: 6px;
            padding-left: 20px;
            padding-top: 10px;
            background-color: white;
        }
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            margin: 0;
            padding: 0;
        }

        /* Container Styles */
        .container {
            max-width: 600px;
            margin: 0 auto;
            padding-top: 0px;
            padding-left: 20px;
            padding-right: 20px;
            padding-bottom: 20px;
            background-color: #ffffff;
            border-left: 1px solid #e0e0e0;
            border-right: 1px solid #e0e0e0;
        }

        /* Header Styles */
        .header {
            text-align: center;
            margin-bottom: 20px;
        }

        .header h1 {
            color: #333333;
            font-size: 24px;
            margin: 0;
            padding: 0;
            }

        /* Content Styles */
        .content {
            margin-bottom: 20px;
        }

        .content p {
            color: #555555;
            font-size: 16px;
            line-height: 1.5;
            margin: 0 0 10px;
            padding: 0;
        }

        .footer {
            text-align: center;
            color: #777777;
            font-size: 14px;
        }

        .container-footer {
            background-color: black;
            max-width: 640px;
            margin: 0 auto;
            border-left: 1px solid black;
            border-right: 1px solid black;
            border-bottom-left-radius: 6px;
            border-bottom-right-radius: 6px;
            padding-left: 0%;
            padding-top: 0px;
        }

        .footer-links {
            margin-left: auto;
            margin-right: auto;
            display: table;
            margin-bottom: 20px;
            padding-top: 20px;
        }

        .icon-round {
            /* float: left; */
            border-radius: 100px;
            background-color: white;
            margin: 0px;
            padding: 0px;
            border: 0px;
            width: 50px;
            height: 50px;
            border: 10px;
            border-color: black;
        }

        .social-icon {
            margin: 0px;
            padding: 0px;
            border: 0px;
            border-color: black;
        }

        .icon-link {
            margin: 0px;
            padding: 0px;
            border: 0px;
            border-color: black;
        }

        .icon-table-cell {
            display: table-cell;
        }

        .company-description {
            margin-left: auto;
            margin-right: auto;
            color: white;
            font-family: Arial, sans-serif;
            text-align: center;
            padding-bottom: 20px;
        }

        .contacts-text {
            border: 0px;
            padding: 1px;
            margin: 0px;
        }

        .table-company-name {
            display: table;
            margin-left: auto;
            margin-right: auto;
            padding: 1px;
        }

        .contacts-text-company-name {
            display: table-cell;
        }

    </style>
</head>
<body>

    <div class="logo-container">
        <!-- <a href="link" class="logo vertical vertical--middle"><img src="cid:{asparagus_cid}" alt="a" title="a" aria-label="a"></a> -->
        <a href="https://alivaria.by/ru/" class="logo vertical vertical--middle"><img src="images\corporate-logo.png" alt="Аливария" title="Аливария" aria-label="Аливария"></a>
    </div>

<div class="container">
    <div class="row">
    
        <div class="header">
        <h1>Debt Collection Email</h1>
        </div>
        <div class="content">
        <p>Dear [Debtor's Name],</p>
        <p>This is a reminder that there is an outstanding balance of $[Outstanding Balance] on your account. The payment was due on [Due Date]. We kindly request that you settle this amount as soon as possible to avoid any further action.</p>
        <p>If you have any questions or need assistance, please don't hesitate to contact our office at [Contact Information].</p>
        <p>Thank you for your immediate attention to this matter.</p>
        <p>Sincerely,</p>
        <p>The Debt Collection Team</p>
        </div>
    </div>
</div>

<div class="container-footer">
    <footer class="footer">
        <div class="footer-links">

            <div class="icon-table-cell">
                <div class="icon-round">
                    <a href="link" target="_blank" class="icon-link">
                        <img src="images\instagram-icon.png" alt="Instagram" class="social-icon" width="50" height="50">
                        <!-- <img src="cid:{asparagus_cid}" alt="Instagram" class="social-icon" width="50" height="50"> -->
                    </a>
                </div>
            </div>

<div class="icon-table-cell">
  <div class="icon-round">
      <a href="link" target="_blank" class="icon-link">
          <img src="images\linkedin-icon.png" alt="LinkedIn" class="social-icon" width="50" height="50">
          <!-- <img src="cid:{asparagus_cid}" alt="LinkedIn" class="social-icon" width="50" height="50"> -->
      </a>
  </div>
</div>

<div class="icon-table-cell">
  <div class="icon-round">
      <a href="link" target="_blank" class="icon-link">
          <img src="images\site-icon.png" alt="Instagram" class="social-icon" width="50" height="50">
          <!-- <img src="cid:{asparagus_cid}" alt="Instagram" class="social-icon" width="50" height="50"> -->
      </a>
  </div>
</div> 

</div>
<div class="company-description">
<div class="table-company-name">
  <p class="contacts-text-company-name" style="padding-right: 4px;">Company Name </p> 
  <p class="contacts-text-company-name">© 2023</p>
</div>
<p class="contacts-text">ID Company</p>
<p class="contacts-text">Company Address</p>
</div>
</footer>
</div>
</body>
</html>

preview:

enter image description here

I hid corporate logo.

So html contains four images: corporate logo, instagram icon, linkedin icon and site icon.

And i use in html code for correct rendering

<img src="cid:{asparagus_cid}"

Then i replace `asparagus_cid` in my python function using format function.

Here is test.py:

import smtplib, os
from dotenv import load_dotenv
from email.message import EmailMessage
from email.utils import make_msgid


# test function
def send_email() -> None:

    # get envoirement variables 
    load_dotenv()
    sender_mail = os.getenv("SENDER_MAIL")
    mail_sender_password = os.getenv("MAIL_SENDER_PASSWORD")
    recipient_mail = os.getenv("RECIPIENT_MAIL")

    # Open the plain text file whose name is in textfile for reading.
    msg = EmailMessage()
    msg.set_content('')

    # set email headers
    msg['Subject'] = f'Email-sending Testing'
    msg['From'] = sender_mail
    msg['To'] = recipient_mail

    # list of files that will add to html-context
    html_files = ["static\\styles.html",
                  "static\\logo.html",
                  "static\\email_template.html",
                  "static\\footer-inst.html",
                  "static\\footer-link.html",
                  "static\\footer-site.html"]

    full_html_conntent = ""
    for html_file in html_files:
        print(html_file)

        # if html file contains image (<img src="...">) element
        if html_file in ["static\\logo.html", "static\\footer-inst.html", "static\\footer-link.html", "static\\footer-site.html"]:

            # set path to image for every html file with images element
            if html_file == "static\\logo.html":
                path_pic = "static\\images\\corporate-logo.png"
            elif html_file == "static\\footer-inst.html":
                path_pic = "static\\images\\instagram-icon.png"
            elif html_file == "static\\footer-link.html":
                path_pic = "static\\images\\linkedin-icon.png"
            elif html_file == "static\\footer-site.html":
                path_pic = "static\\images\\site-icon.png"

            # add to msg html content of evry file with image
            with open(html_file, "r", encoding="utf-8") as file:
                content_html = file.read()
                msg.add_alternative(content_html, subtype='html')
                full_html_conntent += content_html

            # code for correct desplaying logo from documentation and examples
            asparagus_cid = make_msgid()
            msg.add_alternative(content_html.format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')

            with open(path_pic, 'rb') as img:
                msg.get_payload()[1].add_related(img.read(), 'image', 'jpeg',
                                                cid=asparagus_cid)
                
        # if html file don't contains any images
        else:
            with open(html_file, "r", encoding="utf-8") as file:
                html_content = file.read()
                msg.add_alternative(html_content, subtype='html')
                full_html_conntent += html_content

    with open("static\\outpute_email.html", "w", encoding="utf-8") as file:
        file.write(full_html_conntent)

    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.starttls()

    server.login(user=sender_mail, password=mail_sender_password)

    server.sendmail(from_addr=sender_mail,
                    to_addrs=recipient_mail,
                    msg=msg.as_string())


if __name__ == '__main__':
    send_email()

I divided the entire template into its component parts for the correct replacement of images and pass them to msg in a cycle in the above function. Here are parts:

static\\styles.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .logo-container {
            max-width: 620px;
            margin: 0 auto;
            border-top: 1px solid #e0e0e0;
            border-left: 1px solid #e0e0e0;
            border-right: 1px solid #e0e0e0;
            border-top-left-radius: 6px;
            border-top-right-radius: 6px;
            padding-left: 20px;
            padding-top: 10px;
            background-color: white;
        }
        body {
            font-family: Arial, sans-serif;
            background-color: #f5f5f5;
            margin: 0;
            padding: 0;
        }

        /* Container Styles */
        .container {
            max-width: 600px;
            margin: 0 auto;
            padding-top: 0px;
            padding-left: 20px;
            padding-right: 20px;
            padding-bottom: 20px;
            background-color: #ffffff;
            border-left: 1px solid #e0e0e0;
            border-right: 1px solid #e0e0e0;
        }

        /* Header Styles */
        .header {
            text-align: center;
            margin-bottom: 20px;
        }

        .header h1 {
            color: #333333;
            font-size: 24px;
            margin: 0;
            padding: 0;
            }

        /* Content Styles */
        .content {
            margin-bottom: 20px;
        }

        .content p {
            color: #555555;
            font-size: 16px;
            line-height: 1.5;
            margin: 0 0 10px;
            padding: 0;
        }

        .footer {
            text-align: center;
            color: #777777;
            font-size: 14px;
        }

        .container-footer {
            background-color: black;
            max-width: 640px;
            margin: 0 auto;
            border-left: 1px solid black;
            border-right: 1px solid black;
            border-bottom-left-radius: 6px;
            border-bottom-right-radius: 6px;
            padding-left: 0%;
            padding-top: 0px;
        }

        .footer-links {
            margin-left: auto;
            margin-right: auto;
            display: table;
            margin-bottom: 20px;
            padding-top: 20px;
        }

        .icon-round {
            /* float: left; */
            border-radius: 100px;
            background-color: white;
            margin: 0px;
            padding: 0px;
            border: 0px;
            width: 50px;
            height: 50px;
            border: 10px;
            border-color: black;
        }

        .social-icon {
            margin: 0px;
            padding: 0px;
            border: 0px;
            border-color: black;
        }

        .icon-link {
            margin: 0px;
            padding: 0px;
            border: 0px;
            border-color: black;
        }

        .icon-table-cell {
            display: table-cell;
        }

        .company-description {
            margin-left: auto;
            margin-right: auto;
            color: white;
            font-family: Arial, sans-serif;
            text-align: center;
            padding-bottom: 20px;
        }

        .contacts-text {
            border: 0px;
            padding: 1px;
            margin: 0px;
        }

        .table-company-name {
            display: table;
            margin-left: auto;
            margin-right: auto;
            padding: 1px;
        }

        .contacts-text-company-name {
            display: table-cell;
        }

    </style>
</head>

static\\logo.html:


<body>

    <div class="logo-container">
        <a href="link" class="logo vertical vertical--middle"><img src="cid:{asparagus_cid}" alt="a" title="a" aria-label="a"></a>
        <!-- <a href="https://alivaria.by/ru/" class="logo vertical vertical--middle"><img src="images\corporate-logo.png" alt="Аливария" title="Аливария" aria-label="Аливария"></a> -->
    </div>

static\\footer-inst.html:


<div class="container-footer">
    <footer class="footer">
        <div class="footer-links">

            <div class="icon-table-cell">
                <div class="icon-round">
                    <a href="link" target="_blank" class="icon-link">
                        <!-- <img src="images\instagram-icon.png" alt="Instagram" class="social-icon" width="50" height="50"> -->
                        <img src="cid:{asparagus_cid}" alt="Instagram" class="social-icon" width="50" height="50">
                    </a>
                </div>
            </div>

static\\footer-link.html:


<div class="icon-table-cell">
  <div class="icon-round">
      <a href="link" target="_blank" class="icon-link">
          <!-- <img src="images\linkedin-icon.png" alt="LinkedIn" class="social-icon" width="50" height="50"> -->
          <img src="cid:{asparagus_cid}" alt="LinkedIn" class="social-icon" width="50" height="50">
      </a>
  </div>
</div>

static\\footer-site.html:


<div class="icon-table-cell">
  <div class="icon-round">
      <a href="link" target="_blank" class="icon-link">
          <!-- <img src="images\site-icon.png" alt="Instagram" class="social-icon" width="50" height="50"> -->
          <img src="cid:{asparagus_cid}" alt="Instagram" class="social-icon" width="50" height="50">
      </a>
  </div>
</div> 

</div>
<div class="company-description">
<div class="table-company-name">
  <p class="contacts-text-company-name" style="padding-right: 4px;">Company Name </p> 
  <p class="contacts-text-company-name">© 2023</p>
</div>
<p class="contacts-text">ID Company</p>
<p class="contacts-text">Company Address</p>
</div>
</footer>
</div>
</body>
</html>

This is done in order to correctly replace images according to the smtplib documentation.

But when i run the test() function and send the email i get next message with uncorrectly web-element and layout:

enter image description here

I didn't find the solution of this problem...

The solution should not be related to the stack I'm using. Perhaps there are other libraries on how to correctly pass images to the layout

Please help

0

There are 0 best solutions below