1

I am trying to create a bulk email sender. I am struggling to add multiple recipients. I want the script to open contacts.csv that contains multiple email addresses, and send the email to them.

Simply, I need help creating a script that opens the csv file, reads the emails and sends the email to those addresses.

I have tried this but it did not work:

with smtplib.SMTP("smtp.gmail.com:587") as server:
    with open("contacts.csv") as file:
        reader = csv.reader(file)
        next(reader)  # Skip header row
        for name, email in reader:
            server.sendmail(
                sender_email,
                email,text
                #message.format(name=name),
            )

my contacts.csv file:

name, email
john, test1@gmail.com
jake, test2@gmail.com

my emailsender.py file:

import smtplib
from email import encoders 
from email.mime.text import MIMEText 
from email.mime.multipart import MIMEMultipart 

fromaddr = "myemail@gmail.com"
toaddr = "emails@gmail.com"
msg = MIMEMultipart() 
      
msg['From'] = fromaddr 
msg['To'] = toaddr 
msg['Subject'] = "test"
body = "testing"
msg.attach(MIMEText(body, 'plain')) 
      
s = smtplib.SMTP('smtp.gmail.com', 587) 
s.starttls() 
s.login(fromaddr, "password") 
text = msg.as_string() 
s.sendmail(fromaddr, toaddr, text)
print("Email sent!")
s.quit() 
send()
Akkfic
  • 57
  • 8

1 Answers1

2

I have tested this code and it works fine:

import smtplib
from email.mime.text import MIMEText 
from email.mime.multipart import MIMEMultipart 
import csv

emails = []
with open('test.csv', 'r') as file: #open csv file
  reader = csv.reader(file) #init the csv reader
  for row in reader: #iterate through all rows in the csv file
    emails.append(row[1]) #add the second element of every row (the email column) to the list "emails"
  emails.pop(0) #remove the first email which is just the text "email" in the csv file that we don't want
print(emails) #remove if you wish

def sender(recipients, from_email, password, body, subj): #create a sender function. partially adapted from https://stackoverflow.com/a/51931160/8402369
  msg = MIMEMultipart()

  msg['Subject'] = subj
  msg['From'] = from_email
  msg['To'] = (', ').join(recipients)

  msg.attach(MIMEText(body,'plain'))

  server = smtplib.SMTP('smtp.gmail.com', 587)
  server.starttls()
  server.login(from_email, password)
  server.send_message(msg)
  server.quit()


sender(emails, 'youremail@gmail.com', 'your_password', 'Message body', 'Subject') #send all emails

Run and edit the code online

EDIT:

Here's a version with the ability to change the email content based on the csv data:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import csv

csvdata = []
with open('test.csv', 'r') as file:  #open csv file
    reader = csv.reader(file)  #init the csv reader
    for row in reader:  #iterate through all rows in the csv file
        csvdata.append(
            row #instead of adding the email to the array, add the whole row to the array
        )  #add the second element of every row (the email column) to the list "emails"
    csvdata.pop(0)


def sender(
        recipient, name_to_display, from_email, password, body, subj
):  #create a sender function. partially adapted from https://stackoverflow.com/a/51931160/8402369
    msg = MIMEMultipart()

    msg['Subject'] = subj
    msg['From'] = f'{name_to_display} <{from_email}>'
    msg['To'] = recipient

    msg.attach(MIMEText(body, 'plain'))

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    server.login(from_email, password)
    server.send_message(msg)
    server.quit()

your_email = "email@gmail.com"
your_password =  "password"
name_to_display = "The name of the sender that displays in the inbox (your name or whatever you want)"

for item in csvdata:
    name = item[0] #the first column of the csv file is the name
    email = item[1] #the second is the email. if you have more columns get them here like so: item[2] (change the index accordingly)
    print(f'Sending email to {email}')
    body = "Hi " + name + ", The rest of the content goes here"
    subject = "Subject"
    sender(email, name_to_display, your_email, your_password, body, subject)

Run and edit this code online

Notes:

The sender function is partially adapted from here

marsnebulasoup
  • 2,530
  • 2
  • 16
  • 37
  • Thank you for your submission. If I would like to go one step further and include their name from contacts.csv into the body of the email, how would I do this? – Akkfic Aug 20 '20 at 02:52
  • Here is an example body: Hello, (their name), how are you today? @MarsNebulaSoup – Akkfic Aug 20 '20 at 02:53
  • 1
    I'm not sure you can do do it like that because you are sending the same email to multiple people. You could send a separate email to each person, but that would most likely take longer to process for a lot of people – marsnebulasoup Aug 20 '20 at 02:57
  • 1
    All the emails can be the same, however the only variable that needs to change is the name. So is this impossible? @MarsNebulaSoup – Akkfic Aug 20 '20 at 02:58
  • 1
    It's definitely not impossible. Let me type up a quick example of what I was taking about. – marsnebulasoup Aug 20 '20 at 03:00
  • 1
    Sorry it took so long. I was trying to get the sender's name to appear in the email inbox. Anyways, [this](https://repl.it/@marsnebulasoup/FrillySphericalWeb-1) should work. It's not really slow either. I tested it and got two different emails with different names, like you need – marsnebulasoup Aug 20 '20 at 03:20