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()
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
Related
def mail():
import os
import pandas as pd
import smtplib
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import formatdate
from email.mime.multipart import MIMEMultipart
from email import encoders
from PyQt5.QtCore import QDate, Qt
path = 'C:/Users/user/Desktop/pdf/'
contact = 'con1.xlsx'
df = pd.read_excel(str(path)+contact, endcoding ='utf8')
df.set_index('unyong', inplace = True)
now = QDate.currentDate()
filenm = [f for f in os.listdir(path) if f.endswith('.pdf')]
unyong_nm = []
for w in filenm:
a = w.find('_')
b = w.rfind('_')
unyong_nm.append(w[a+1:b])
unyong_nm = list(set(unyong_nm))
for i in range(0,len(unyong_nm)):
send_from = 'ss#ddd'
recipients = df.loc[unyong_nm[i],'email']
send_to = ",".join(recipients)
attach = [s for s in filenm if s.find(unyong_nm[i]) >-1 ]
username = 'sss#ssss'
password = 'sss'
subject = ('111'+now.toString('yyyy.MM')+'_'+unyong_nm[i]+str(i+1))
text = ('hi')
msg = MIMEMultipart()
msg['From'] = send_from
msg['To']= send_to
msg['Subject'] = subject
msg['Date']=formatdate(localtime=True)
filename_match = [s for s in filenm if s.find(unyong_nm[i]) >-1 ]
for file in filename_match:
part =MIMEBase('application','octet-stream')
part.set_payload(open(str(path)+file, 'rb').read())
encoders.encode_base64(part)
part.add_header('Content-Disposition','attachment', filename =file)
msg.attach(part)
msg.attach(MIMEText(text))
mailServer = smtplib.SMTP("smtp.sssss.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(username,password)
mailServer.sendmail(send_from, send_to, msg.as_string())
mailServer.close()
hi i have a problem with the email with attachment for statement.
the results of below def mail(),
multiple emails was sent to one person. (<- this is a error)
I want to send a each specific reciever with specific multiple attachments only once
why multiple email sented with diffrent number of attachements to one person.
the reciever have the 2 emails with a 1 attachment and, simultaneouly 2 attachment.
I want to send a email containg 2 attachments
please help me.
*CF) path containg thoes files:
['2221_sss_love.pdf', '2221_sss_happy.pdf', '2221_ddd_sad.pdf', '2221_ddd_lucky.pdf', 'con1.xlsx']
*result
unyong_nm = ['sss','ddd']
filenm = ['2221_sss_love.pdf', '2221_sss_happy.pdf', '2221_ddd_sad.pdf', '2221_ddd_lucky.pdf']
*CF) con1.xlsx file contenxt:
unyong email
sss 111#aaa
sss 777#bbb
ddd 666#sss
ddd 444#ccc
The code is sending an email for each attachment. By dedenting the mail-sending code, an email will be sent for each set of attachments grouped by 'ddd' or 'sss'.
for file in filename_match:
part = MIMEBase("application", "octet-stream")
part.set_payload(open(file, "rb").read())
encoders.encode_base64(part)
part.add_header("Content-Disposition", "attachment", filename=file)
msg.attach(part)
msg.attach(MIMEText(text))
# Send mail outside the file grouping loop
mailServer = smtplib.SMTP("localhost", 1025)
mailServer.ehlo()
mailServer.sendmail(send_from, send_to, msg.as_string())
mailServer.close()
The recipient selection code
recipients = df.loc[unyong_nm[i],'email']
send_to = ",".join(recipients)
might need to be changed, I can't tell because the contents of the dataframe aren't provided in the question.
I am using the csv library to pull data to into an email body. I am pulling certain columns from the csv for the body. I am using a junk gmail account to test. I'm just confused on how to use the for loop. If I'm correct, you need a for loop to read the rows then a for loop to email out. I did read Reading and Writing CSV Files but was uncertain how to implement it with smtplib.
import csv, smtplib, ssl
message = """Subject: Your Title
{supervisor} {title} {start}"""
from_address = "test#gmail.com"
password = input("Type your password and press enter: ")
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(from_address, password)
with open('test.csv','rb') as file:
reader = csv.reader(file, delimiter=',')
next(reader)
#start = []
#title = []
#supervisor = []
for row in reader:
title = row[3]
start = row[0]
supervisor = row[4]
for supervisor, title, start in reader:
server.sendmail(
from_address,
Email,
message.format(supervisor=supervisor, start=start, title=title)
)
print('Emails were sent successfully!')
CSV File:
StartDate,Employee Name,PC,Title,Supervisor Name,email
12/9/2019,Katti M. Ricke,289,Recruiter,Courtney Clark,test#gmail.com
Probably if you use pandas for to handle the csv could be more easy ..for install pandas just pip install pandas
import pandas as pd
import io
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# read csv using pandas and then convert the csv to html string ....this code later will add into body
str_io = io.StringIO()
df = pd.read_csv('test.csv')
df.to_html(buf=str_io)
table_html = str_io.getvalue()
print(table_html)
sender_email = "mymail#gmail.com"
receiver_email = "anothermail#gmail.com"
password = "mypass"
message = MIMEMultipart("alternative")
message["Subject"] = "Subject: Your Title"
message["From"] = sender_email
message["To"] = receiver_email
text = """\
Subject: Your Title"""
html = """\
<html>
<body>
<p>{table_html}</p>
</body>
</html>
""".format(table_html=table_html)
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)
# Send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
server.sendmail(
sender_email, receiver_email, message.as_string()
)
I have a working send email script which takes txt file and send it encoded.
i want to be able to design (html) this encoded txt in the email body.
i know how generally design a text in email body but i cant design the encoded txt in the html.
i want to combine the two scripts and be able to design the encoded text ( first script output) into the html design of the second script
first script send email ( Works but undesigned body ):
import smtplib
from email.message import EmailMessage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# mailing cofig:
ID = 'XX
PASSWORD = XX
email_reciever = XX
filename = r".\Reports\Report.txt"
def send_email(subject, msg):
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login(ID, PASSWORD)
message = 'Subject:{}\n\n{}'.format(subject, msg)
server.sendmail(ID, email_reciever, message)
# server.sendmail(ID, email_reciever, msg.as_string())
print('Succes')
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Your BeeHero Report'
msg['From'] = ID
msg['To'] = email_reciever
with open(filename, "r") as filename:
text = ''.join(filename.readlines()[1:])
msg.set_payload(text.encode())
subject = "BeeHero Report"
send_email(subject, msg)
output:
https://imgur.com/a/g6m0WKt
Second script ( designed body but not encoded as the first output)
# Sending email script Amit
import smtplib
from email.message import EmailMessage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# mailing cofig:
ID = XX
PASSWORD = XX
email_reciever = XX
filename = r".\Reports\Report.txt"
def send_email(msg):
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo()
server.login(ID, PASSWORD)
server.sendmail(ID, email_reciever, msg.as_string())
print('Succes')
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Your BeeHero Report'
msg['From'] = ID
msg['To'] = email_reciever
with open(filename, "r") as filename:
text = ''.join(filename.readlines()[1:])
html = (f"""
<!DOCTYPE html>
<html>
<body>
<h1 style="color:SlateGray;">{text}</h1>
</body>
</html>
""")
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
msg.attach(part1)
msg.attach(part2)
send_email(msg)
output:
https://imgur.com/a/5wqUoSa
I am working on a python script to send email to my customer with a survey. I will send only one email with all my customers's emails in the BCC field so that I do not need to loop through all the emails. Everything works fine when I tested sending emails to my company's coleagues and also when I sent to my personal email, but whenever I send to a gmail account, the BCC field appears to not be hidden and show all the emails. I found this post Email Bcc recipients not hidden using Python smtplib and tried that solution as well, but as I am using a html body email, the emails were shown inside the body. Can anyone help me on this one?
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
def send_survey_mail():
template_path = 'template.html'
background_path = 'image.png'
button_path = 'image2.png'
try:
body = open(template_path, 'r')
msg = MIMEMultipart()
msg['Subject'] = 'Customer Survey'
msg['To'] = ', '.join(['myemail#domain.com.br', 'myemail2#domain.com'])
msg['From'] = 'mycompany#mycompany.com.br'
msg['Bcc'] = 'customer#domain.com'
text = MIMEText(body.read(), 'html')
msg.attach(text)
fp = open(background_path, 'rb')
img = MIMEImage(fp.read())
fp.close()
fp2 = open(button_path, 'rb')
img2 = MIMEImage(fp2.read())
fp2.close()
img.add_header('Content-ID', '<image1>')
msg.attach(img)
img2.add_header('Content-ID', '<image2>')
msg.attach(img2)
s = smtplib.SMTP('smtpserver')
s.sendmail('mycompany#mycompany.com.br',
['myemail#domain.com.br', 'myemail2#domain.com', 'customer#domain.com'],
msg.as_string())
s.quit()
except Exception as ex:
raise ex
send_survey_mail()
I removed the following line from the code and tried again. Now the email is not sent to my customer's Gmail email.
msg['Bcc'] = 'customer#gmail.com'
Just do not mention bcc mails in msg['To'] or msg['Cc']. Do it only in server.sendmail()
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from_addr = "your#mail.com"
to_addr = ["to#mail.com", "to2#mail.com"]
msg = MIMEMultipart()
msg['From'] = from_addr
msg['To'] = to_addr
msg['Subject'] = "SUBJECT"
body = "BODY"
msg.attach(MIMEText(body, 'plain'))
filename = "FILE.pdf"
attachment = open('/home/FILE.pdf', "rb")
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)
msg.attach(part)
server = smtplib.SMTP('.....', 587)
server.starttls()
server.login(from_addr, 'yourpass')
text = msg.as_string()
server.sendmail(from_addr, to_addr + [bcc#mail.com], text)
server.quit()
Did you try not to define the msg['BCC'] field? Setting this field forces it to be included. It is sufficient that the BCC email address is in the sendmail command's destination address list. Take a look at this question.
MAIL_FROM = default#server.com
MAIL_DL = default#server.com
def send(to, cc, bcc, subject, text, html):
message = MIMEMultipart("alternative")
message["Subject"] = subject
message["From"] = MAIL_FROM
message["To"] = to
message["Cc"] = cc + "," + MAIL_DL
if html is not None:
body = MIMEText(html, "html")
else:
body = MIMEText(text)
message.attach(body)
server = smtplib.SMTP(MAIL_SERVER)
server.set_debuglevel(1)
server.sendmail(MAIL_DL, to.split(",") + bcc.split(","), message.as_string())
server.quit()
return {
"to": to,
"cc": cc,
"bcc": bcc,
"subject": subject,
"text": text,
"html": html,
}
I am trying to send an email with smtp in python 3.3 to a recipient listed in a text file.
The error I receive is:
session.sendmail(sender, recipient, msg.as_string())
smtplib.SMTPRecipientsRefused: {}
Where is the error in sendmail? Thanks!
Full code below:
#!/usr/bin/python
import os, re
import sys
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
mails = open('/path/emails.txt','r+')
mailList = mails.read()
mailList = [i.strip() for i in mails.readlines()]
directory = "/path/Desktop/"
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
sender = 'Sender#gmail.com'
password = "Sender'sPassword"
recipient = [i.strip() for i in mails.readlines()]
subject = 'Python (-++-) Test'
message = 'Images attached.'
def main():
msg = MIMEMultipart()
msg['Subject'] = 'Python (-++-) Test'
msg['To'] = recipient
msg['From'] = sender
files = os.listdir(directory)
pngsearch = re.compile(".png", re.IGNORECASE)
files = filter(pngsearch.search, files)
for filename in files:
path = os.path.join(directory, filename)
if not os.path.isfile(path):
continue
img = MIMEImage(open(path, 'rb').read(), _subtype="png")
img.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(img)
part = MIMEText('text', "plain")
part.set_payload(message)
msg.attach(part)
session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
session.ehlo()
session.starttls()
session.ehlo
session.login(sender, password)
session.sendmail(sender, recipient, msg.as_string())
session.quit()
if __name__ == '__main__':
main()
You want to double-check your recipients code. It looks like you're trying to consume the contents of the file more than once, which won't work--the file objects should be understood as a stream, not a block of data, so once you've done f.read() or [i.strip() for i in mails.readlines()] one time, that stream is empty, so doing it a second time is going to produce an empty list. You should check this yourself by printing recipient
then try this:
mails = open('/path/emails.txt','r+')
#mailList = mails.read()
#mailList = [i.strip() for i in mails.readlines()]
directory = "/path/Desktop/"
SMTP_SERVER = 'smtp.gmail.com'
SMTP_PORT = 587
sender = 'Sender#gmail.com'
password = "Sender'sPassword"
recipient = [i.strip() for i in mails.readlines()]
print(recipient)
subject = 'Python (-++-) Test'
message = 'Images attached.'
Now you should have the a populated recipient list, and on to the next issue!