Automatically generate useful emails to keep key stakeholders in the know

Photo by Artem Sapegin on Unsplash.

With the power of Python’s automation to reduce manual effort, whenever we complete a task, it’s always a good approach to generate a report and send it to people along with an email including the process results, a description, and maybe some graphs as attachments.

In any organization with several processes, reports get generated and sent to multiple teams in addition to notifications if the processes are not running or failed. Basically, for every situation where we automate, it’s always good to send an email notification after the process is complete.

First Things First: Importing Required Modules

We will be using the modules below to generate an HTML version of the mail body — including an image — attach a report file, and send the email to an individual or distribution list.

import smtplib
from email.message import EmailMessage
from email.utils import make_msgid
import mimetypes

Creating a Simple HTML File for Email Body in Message

Now, let’s create a simple HTML file (mail_template.html) which we will use in the email as a template to include the image and text to format for beautification. I will explain below on the template and identify which variables are used in the template.

Final Code to Send Email With Attachment

Below is the final code that will read the template file to create a beautiful email body, embed an image as the header, and include a dynamic text in the body that can be passed on as the function argument and attach the file.

I will try to explain the individual steps below with individual blocks.

Now, we will look over each section from the function above and review what they mean while generating the email.

Files Used in the Program

mail_template_file = os.path.join(path_dir, 'mail_template.html')
mail_image_file = os.path.join(path_dir, 'mail_header_image.jpg')
rep_image_file = os.path.join(path_dir, 'report.pdf')

I have used OS module functions so that this approach can be used regardless of if the program is running in Windows or Linux.

mail_template.html will have a basic HTML version of the email template. I have used a table for a better row-level alignment.

  • The image_cid variable used in the first row will be a placeholder for the header image mail_header_image.jpg.
  • The email_body variable in the second row will be for the email body text.

report.pdf is the file that will be attached to the email.

Address Used for Sending Emails

Nothing to explain here. I prepared the IDs to whom the email has to be delivered and created a list so that it can be used to send to multiple people or teams.

Read the HTML Template File

Read the HTML template file and embed the email body and image into the email.

Set an alternative HTML body with the image:

temp_file = open(mail_template_file, “r”)
if temp_file.mode == ‘r’:
contents =

Embed the email body with the text we receive as an argument using the variable mapping in the HTML template:

filemsg.add_alternative(contents.format(image_cid=image_cid[1:-1], email_body=email_body), subtype=’html’)

Embed the Image As the Header in the Email Body

Read the image file that we want to embed into the email just to look nice and get the reader’s attention. Here, we will be getting the type of the image, and that will be used in the message arguments. Also, this will be directly placed in the image_cid variable in the HTML template.

Now embed the image as a header at the top of the email body with open(mail_image_file, ‘rb’) as img.

Know the content type of the image:

maintype, subtype = mimetypes.guess_type([0].split(‘/’)

Embed the image using the variable mapping in the HTML template file:

msg.get_payload()[1].add_related(, maintype=maintype, subtype=subtype, cid=image_cid)

Attach a PDF Report to the Email

After embedding the image into the email, let’s include an attachment too so that both cases can be covered based on individual use cases.

Here, we are opening a PDF document and adding it to the message as an attachment. The process again involves identifying the type of the file, but the difference is that we embedded into the mail using add_related, whereas we are now attaching something to the message using add_attachment.

Now add the report as an attachment to the email with open(rep_image_file, ‘rb’) as img2.

Know the content type of the image:

maintype, subtype = mimetypes.guess_type([0].split(‘/’)

Attach the report file to the email:

msg.add_attachment(, maintype=maintype, subtype=subtype, filename=”Report.pdf”)

Send the Email

Finally, send the email using an SMTP server and exit the process:

smtp_email = smtplib.SMTP('')
smtp_email.sendmail(from_id, to_addrs, msg.as_string())


This is a very simple process where we embed/attach images or files to the email message and send it to an individual/team using an SMTP server. You can directly use the function and call using Subject and email body as arguments after modifying the email server domain information.

send_report_mail( "Story completed", "Medium Story is completed and email notification is being sent" )