Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Sending Multiple Emails From a CSV File

Give Feedback

You may come across the situation, where you want to send a certain message to different contacts. Maybe you also need to slightly change the message for each receiver. In this video, you’ll learn how to use CSV files to do exactly that! In this case you are a teacher, who wants to inform his students about their grades.

RetiringInComo on July 5, 2019

Thanks Joe!!

Learned a ton , also got it to work at work on Outlook. Have one question though can’t seem to combine the Multiple Emails with Multiple Attachments? Any advice?

Joe Tatusko RP Team on July 8, 2019

You’re welcome! How do you have your code structured?

Let me know what type of error you’re seeing as well!

RetiringInComo on July 9, 2019

import email, smtplib, ssl, csv

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

subject = "An email with attachment from Python"
body = "This is an email with attachment sent from Python"
sender_email = "generic@blah.com"
#receiver_email = ""


# Create a multipart message and set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Bcc"] = receiver_email  # Recommended for mass emails

# Add body to email
message.attach(MIMEText(body, "plain"))

filename = "test.xlsx"  # In same directory as script

# Open PDF file in binary mode
with open(filename, "rb") as attachment:
    # Add file as application/octet-stream
    # Email client can usually download this automatically as attachment
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

# Encode file in ASCII characters to send by email    
encoders.encode_base64(part)

# Add header as key/value pair to attachment part
part.add_header(
    "Content-Disposition",
    f"attachment; filename= {filename}",
)

# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()

# Log in to server using secure context and send email

#with smtplib.SMTP("mailhost:25") as server:
    #server.sendmail(sender_email, receiver_email, text)

with smtplib.SMTP("mailhost:25") as server:
    with open("contacts_file.csv") as file:
        reader = csv.reader(file)
        next(reader)  # Skip header row
        for name, email, grade in reader:
            server.sendmail(
                sender_email,
                email,text
                #message.format(name=name,grade=grade),
            )

RetiringInComo on July 9, 2019

This works but sends the same message and attachment. I commented out the message.format last line since it is not supported with Mime.Base. Ultimately what I am trying to do would be to have a csv file that has name, message, attachment as the headers and use that file to send multiple emails to different people and include different attachments.

So to use your example what if you also wanted to send those three students a copy of their report (lets say the reports were excel files). Then Ron Obvious would get his email stating he got a B+ and it would also include an excel attachment, Killer Rabbit would get his grade and his own attachment etc…

Joe Tatusko RP Team on July 11, 2019

Gotcha! So what you would want to do is save the attachment filepath in your csv.

Try to structure your code something like the following:

open the csv file -> loop through the rows -> create your email object -> open attachment and attach to email -> send email

It looks to me like you’re creating the email object, attaching your file, and then looping through the contacts csv so the same email object and attachment get sent over and over. Let me know if that makes sense!

Abby Jones on July 15, 2019

I cannot proceed any further, I am getting this:

Traceback (most recent call last):
  File "/home/abbyrjones72/Documents/remote_repos/emailer/email.py", line 1, in <module>
    import smtplib, ssl
  File "/home/abbyrjones72/anaconda3/lib/python3.7/smtplib.py", line 47, in <module>
    import email.utils
  File "/home/abbyrjones72/Documents/remote_repos/emailer/email.py", line 17, in <module>
    with smtplib.SMTP_SSL("stmp.gmail.com", 465, context=context) as server:
AttributeError: module 'smtplib' has no attribute 'SMTP_SSL'

Here is my code:

import smtplib, ssl
import csv


message = """\
    From: {sender}
    To: {email}
    Subject: Your Grades

    Hi {name}, your grade is {grade}.

    """
sender = "abbyrjones72dev@gmail.com"
password = input("Please enter a password: ")
context = ssl.create_default_context()

with smtplib.SMTP_SSL("stmp.gmail.com", 465, context=context) as server:
    server.login(sender, password)
    with open("contacts.csv") as file:
        reader = csv.reader(file)
        # skip first header row
        next(reader)
        for name, email, grade in reader:
            server.sendmail(
                sender,
                email,
                message.format(sender=sender, email=email, name=name, grade=grade),
            )

Dan Bader RP Team on July 15, 2019

@Abby: The problem is that your script is called email.py which shadows (hides) Python’s built-in email module. So instead of importing the email module from the standard library Python is trying to import your local email.py script—which doesn’t have an smtplib class, hence the AttributeError.

The easiest way to solve this is to rename your local email.py script file to something else :) More info here in this StackOverflow thread.

RetiringInComo on July 15, 2019

Thanks for the clue, got this to work fabiously!!

import email, smtplib, ssl, csv

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

from_address = ""


with smtplib.SMTP("mailhost:25") as server:
    with open("contacts_file.csv") as file:
            reader = csv.reader(file)
            next(reader)  # Skip header row
            for name, subject_line, body, email, grade, attach in reader:

                # Create a multipart message and set headers
                message = MIMEMultipart()
                message["From"] = from_address
                message["To"] = email
                message["Subject"] = subject_line

                filename = str(attach)

                # Add body to email
                message.attach(MIMEText(body, "plain"))

                with open(filename, "rb") as attachment:
                    # Add file as application/octet-stream
                    # Email client can usually download this automatically as attachment
                    part = MIMEBase("application", "octet-stream")
                    part.set_payload(attachment.read())  

                    # Encode file in ASCII characters to send by email    
                    encoders.encode_base64(part)

                    # Add header as key/value pair to attachment part
                    part.add_header(
                    "Content-Disposition",f"attachment; filename= {filename}",)

                # Add attachment to message and convert message to string
                message.attach(part)
                text = message.as_string()

                # Use server to send email
                server.sendmail(from_address, email, text)

Abby Jones on July 16, 2019

No, this was only after my original file main.py did the same thing.

Joe Tatusko RP Team on July 16, 2019

That’s great! Glad you were able to work it out :D

Abby Jones on July 16, 2019

Nothing worked out lol, it doesn’t work.

Abby Jones on July 16, 2019

I’m sorry, I will figure it out.

Abby Jones on July 16, 2019

It is now working. I made some transcription errors in a few places. Frustration will do that. Thank you Dan and Joe!

Joe Tatusko RP Team on July 16, 2019

Sorry, was replying to RetiringInComo haha

Awesome that you got it too! Glad we (well, mainly Dan :P) could help out.

Abby Jones on July 16, 2019

Yes, I am going to give that link full attention after this fiasco. This really is yet another wonderful tutorial.

beauenslow on Aug. 9, 2019

Is there a way to send multiple emails from a csv file and have the message sent as html. I have been having trouble making this work. Can you help?

Joe Tatusko RP Team on Aug. 13, 2019

Sure thing! This would be similar to RetiringInComo’s question above. You need to structure your code in a way that you’re making an HTML email for each row of the CSV:

open the csv file -> loop through the rows -> create your HTML email object -> send email

Where this gets tricky is what you put in the ‘body’ column of the CSV. I’d start with adding the HTML strings directly into the CSV, then start working at how you could keep the critical information in the CSV and use formatted strings to make an HTML template that is kept outside of the CSV

Kalesis on Sept. 7, 2019

Hello, excellent course.

If with gmail to test we add “my +”, which is the simile for Office365 / Outlook, 7 Yahoo, etc.

Thank you

Become a Member to join the conversation.