Python Sending Emails with Attachments

Johnny Chan
2 min readJun 15, 2021

The post shares the knowledge on how to build a python script to send email with attachment. Keywords: SMTP, DataFrame, StringIO

from Joanna Kosinska @ Unsplash

In my previous post, I shared the knowledge of how to configure a Gmail account and use Python’s SMTP module to build an email server class. This technique comes in handy when you need to constantly monitor the health of your application while you don’t necessarily want to build a full-fledge dashboard. This post takes it further to illustrate how to send email with an attachment. The approach is not as trivial as I originally thought. I had to do some research on how to attach the data (i.e. Pandas DataFrame) without needing to save it to the working directory. This trick is useful when you are working in the cloud environment where you don’t necessarily have the save option.

  1. Configure the email service

You can refer to my previous post Python Gmail Setup Guide and Code Example for accessing email with less secure app.

2. Save a dataframe to csv and attach to the email

To accomplish this task, you need the following modules

from email.mime.text import MIMETextfrom email.mime.multipart import MIMEMultipartfrom email.mime.application import MIMEApplicationfrom io import StringIO

To attach a dataframe as a csv, you need to use the StringIO module. Initalize a textString instance and save a dataframe with the csv format to it. Basically, the testString instance is acting like a memory buffer, which allows you to save the data to the memroy instead of the hard dish.

textStream = StringIO()
df.to_csv(textStream,index=False)

Then you need to extract the value from the memory and attach to the message object.

msg = MIMEMultipart()
msg.attach(MIMEApplication(textStream.getvalue(), Name=filename))

Along with the email subject and body text, the entire workflow looks like this

msg = MIMEMultipart()msg['Subject'] = subjectmsg['From'] = smtp_usermsg['To'] = recipientmsg.add_header('Content-Type','text/html')msg.attach(MIMEText(message, 'html'))textStream = StringIO()df.to_csv(textStream,index=False)msg.attach(MIMEApplication(textStream.getvalue(), Name=filename))

Feel free to check out my Github repo on the full version of codes. Thanks for reading!

--

--