This article will explore how to send email with attachment in Python and how it can be integrated in your existing data science projects.

The technique used in this article assumes that the reader has basic understanding of the structure of sending basic emails with Python.

Table of Contents


Introduction

Sending emails with attachments is a great help to the projects in production. For example, it can be integrated to send the log with details after each successful run of your program (and much more).

So what do we need to send an email with attachment using Python? Actually not that much: some Python programming skills and knowledge of the needed libraries.

As in the tutorial on basic emails with Python, we will work with a Gmail address (but you can extend this to any other email service provider.


Create a multipart message in Python

To continue in this article, please import the required libraries:


import smtplib 

from email.mime.base import MIMEBase 
from email.mime.multipart import MIMEMultipart 
from email.mime.text import MIMEText
from email import encoders

Unlike the basic text email senders in Python, we will need to construct each part of our message separately. This means that we will make each part separately and then assemble it into one message object.

Step 1:

First, we will define our sender and recipient addresses:


fromaddr = 'SENDER EMAIL ADDRESS'
toaddr = 'RECIPIENT EMAIL ADDRESS'

Step 2:

Then let’s make an instance of MIMEMultipart() class. This is a class for MIME messages that contains multiple parts which are then merged together into a message that we will be sending:


msg = MIMEMultipart()

Step 3:

As the next step, we want to specify the specific parts of our msg object. We will add the sender and recipient email addresses to it, and its subject:


msg['From'] = fromaddr

msg['To'] = toaddr

msg['Subject'] = 'This is the subject of my email'

Step 4:

Next, we are going to work on the body of the email. Things here require a little more attention than the previous part so far. Let’s take a look at the code and discuss it further:


body = 'This is the body of my email'

msg.attach(MIMEText(body))

We first create a string with the text content that we want to use in your email and store it as body. Then, we use the attach() method of msg object (which is an instance of MIMEMultipart() class) to add it to our email.
One important note, when we add it to our msg object, we need to use MIMEText() which is used to create MIME objects of type text (string).


Add .docx attachment to email using Python

In this section of the article we will go through the part of adding a file as attachment to an email. This part of the article has the most complicated code compared to the other sections. But nothing to worry, we are going to discuss each step in detail.

For now, let’s assume we would like to add a simple word document (myfile.docx).

Step 1:

Let’s first define a paths the files we want to use as attachments and keep it as a list called files:


files = ['PATH TO FILE 1', 'PATH TO FILE 2', 'OTHER FILES']

Step 2:

Next, we will open this file in a read/write mode and do some manipulations with it:


for filename in files:

    attachment = open(filename, 'rb')

    part = MIMEBase("application", "octet-stream")

    part.set_payload(attachment.read())

    encoders.encode_base64(part)

    part.add_header("Content-Disposition",
    f"attachment; filename= {filename}")

    msg.attach(part)

msg = msg.as_string()
  • Initially we read our Word file as attachment in read/write mode.
  • Then we create an instance of MIMEBase() class with “application” and “octet-stream” as parameters and store it as part. What this does is specifies the content type, in this case it’s a binary file. The reason we are doing this is because we want this file to be open in the email application (such as Gmail, Outlook, and so on).
  • Now we need to change the payload to encoded form by using set_payload() method of MIMEBase() class and pass the read file as an argument to it.
  • Once we have the encoded form, we will set the encoders to Base64 by using .encode_base64(part). In computer science, Base64 is a binary-to-text encoding.
  • As you can trace the code, part variable is an instance of MIMEBase() class to which we applied some modifications. Now what we want to do is use .add_header() method with a particular “Content-Disposition” argument.
  • Lastly, we will add it to out msg using .attach() method and convert it to string format.

Wonderful! Our email is built and constructed in the correct format. We are ready to send it!


Send email using Python

All we have left to do is to login into our email server and send the email with the msg as its content.

In this article we will send it using the Gmail email address:


try:
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo()
    server.starttls()
    server.login(fromaddr, 'gpjeukeadncvznul')
    server.sendmail(fromaddr, toaddr, msg)
    server.quit()
    print('Email sent successfully')
except:
    print("Email couldn't be sent")

For detailed explanations about this code chunk, please refer to my previous article on sending basic emails using Python.


Conclusion

Your complete version of this code should look like this:


import smtplib 

from email.mime.base import MIMEBase 
from email.mime.multipart import MIMEMultipart 
from email.mime.text import MIMEText
from email import encoders


fromaddr = 'SENDER EMAIL ADDRESS'
toaddr = 'RECIPIENT EMAIL ADDRESS'


msg = MIMEMultipart()


msg['From'] = fromaddr

msg['To'] = toaddr

msg['Subject'] = 'This is the subject of my email'


body = 'This is the body of my email'

msg.attach(MIMEText(body))


files = ['PATH TO FILE 1', 'PATH TO FILE 2', 'OTHER FILES']


for filename in files:

    attachment = open(filename, 'rb')

    part = MIMEBase("application", "octet-stream")

    part.set_payload(attachment.read())

    encoders.encode_base64(part)

    part.add_header("Content-Disposition",
    f"attachment; filename= {filename}")

    msg.attach(part)

msg = msg.as_string()


try:
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo()
    server.starttls()
    server.login(fromaddr, 'gpjeukeadncvznul')
    server.sendmail(fromaddr, toaddr, msg)
    server.quit()
    print('Email sent successfully')
except:
    print("Email couldn't be sent")

This article focused on exploring the process on how to send email with .docx attachment in Python. It should be a good foundation to understand the process and have the knowledge to integrate it into an existing data science project.

Feel free to leave comments below if you have any questions or have suggestions for some edits.