Python/smtplib - automation for sending email - python

I am developing an application to automate the sending of emails from the collection department where I work. It consists of accessing an excel spreadsheet, reading the column that is missing the payment and sending an automatic email to the customer. The code works, but it sends the email only to the last person who did not make the payment and not to everyone. can you help me? Follow the code below:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
from datetime import date
import openpyxl
wb = openpyxl.load_workbook('C:/temp/cobranca.xlsx')
sheet = wb['Sheet1']
lastCol = sheet.max_column
latestMonth = sheet.cell(row=1, column=lastCol).value
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'ok':
name = sheet.cell(row=r, column=1).value
email = sheet.cell(row=r, column=2).value
unpaidMembers[name] = email
print(unpaidMembers)
# create message object instance
msg = MIMEMultipart()
# setup the parameters of the message
password = "example"
msg['From'] = "example#example.com"
msg['To'] = email
msg['Subject'] = "%s - Honorário em aberto." % (name)
for name, email in unpaidMembers.items():
body = "Prezado(a) %s. \n \n Em nosso sistema consta, em sua conta, o honorário referente ao mês %s/2020 em aberto, pedimos sua regularização imediata. \n \n Caso o pagamento já tenha sido efetuado, por favor, desconsidere este e-mail. \n \n \n Att, \n OMNIA Tecnologia" % (
name, latestMonth)
print('Sending email to %s...' % email)
# add in the message body
msg.attach(MIMEText(body))
# create server
server = smtplib.SMTP('stmp.example.net', 587)
server.starttls()
# Login Credentials for sending the mail
server.login(msg['From'], password)
# send the message via the server.
server.sendmail(msg['From'], msg['To'], msg.as_string())
server.quit()
print("successfully sent email to %s:" % (msg['To']))

msg['To'] can be given a list of email addresses. Possibly making a list as shown below is an option.
email=[]
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'ok':
name = sheet.cell(row=r, column=1).value
email.append(sheet.cell(row=r, column=2).value)
unpaidMembers[name] = email
print(unpaidMembers)
then
msg['To'] = email

Related

smtlib not send email to email address from column list of pandas dataframe

Dears
I have a Code Connect to Oracle DB, get query as Daraframe and send email to receiver that exist in a column
As I Test When I set test_reciver argument to an email address test_reciver Email received
but when I set (email Receiver) to the column of data frame, Email not received
#send mail function
def send_email(subject,to,cc,body):
sender_email = 'test#test.com'
receivers = to
host = "bulkmail.test.com"
server = smtplib.SMTP(host)
msg = MIMEText(body)
msg['Subject'] = subject
msg['to'] = to
msg['cc'] = cc
server.sendmail(sender_email,to,msg.as_string())
server.quit()
query = "select * from sometable"
test_reciver = "myemail#test.com"
con = cx_Oracle.connect(user_db,password_db,dsn_tns,encoding="UTF-8", nencoding="UTF-8")
cc = 'emailcctest#test.com'
df = pd.read_sql_query(query,con, index_col=None).head(1)
df = df.reset_index()
for index, row in df.iterrows():
print(row['EMAIL'])
subject = 'please clarify your Workgroup in SDM '
to = row['EMAIL']
body = 'sample body'
send_email(subject, to, cc, body)
con.close()
it is solved by sending email as an object with send_message instead of sendmail for smtplib
#send mail function
def send_email(subject,to,cc,body):
host = "bulkmail.test.com"
server = smtplib.SMTP(host)
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = 'test#test.com'
msg['to'] = to
msg['cc'] = email_cc
serve.send_message(msg)
server.quit()

Send gmail with multiple recipients

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

Automating email delivery

I took an example of automation from a book (Automate tasks with Python) which consists of opening and reading a spreadsheet and checking if the fee has been paid, if not, send an email to the client informing him. But when I run the code it doesn't show any error, but also, nothing happens. I would appreciate it if you could help me, and still recommend a library to carry out the process, if necessary.
Follow the code below:
import openpyxl, smtplib, sys
wb = openpyxl.load_workbook('C:/temp/cobranca.xlsx')
sheet = wb['Sheet1']
lastCol = sheet.max_column
latestMonth = sheet.cell(row=1, column=lastCol).value
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'ok':
name = sheet.cell(row=r, column=1).value
email = sheet.cell(row=r, column=2).value
unpaidMembers[name] = email
smtpObj = smtplib.SMTP('mail.omnia.net.br', 465)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('dp.contabil#omnia.net.br', sys.argv[1])
for name, email in unpaidMembers.items():
body = "Subject: %s dues unpaid. \n Dear %s, \n Records show that you have not paid dues for %s. Please make this payment as soon as possible. Thank you!'" % (latestMonth, name, latestMonth)
print('Sending email to %s...' % email)
sendmailStatus = smtpObj.sendmail('dp.contabil#omnia.net.br', email, body)
if sendmailStatus != {}:
print('There was a problem sendind email to %s: %s' % (email, sendmailStatus))
smtpObj.quit()
Here is an example which I used:
import smtplib
from string import Template
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
MY_ADDRESS = 'XYZ#gmail.com'
PASSWORD = 'YourPassword'
def get_contacts(filename):
names = []
emails = []
with open(filename, mode='r', encoding='utf-8') as contacts_file:
for a_contact in contacts_file:
names.append(a_contact.split()[0])
emails.append(a_contact.split()[1])
return names, emails
def read_template(filename):
with open(filename, 'r', encoding='utf-8') as template_file:
template_file_content = template_file.read()
return Template(template_file_content)
def main():
names, emails = get_contacts('C:/Users/xyz/Desktop/mycontacts.txt') # read contacts
message_template = read_template('C:/Users/xyz/Desktop/message.txt')
s = smtplib.SMTP(host='smtp.gmail.com', port=587)
s.starttls()
s.login(MY_ADDRESS, PASSWORD)
for name, email in zip(names, emails):
msg = MIMEMultipart() # create a message
message = message_template.substitute(PERSON_NAME=name.title())
print(message)
msg['From'] = MY_ADDRESS
msg['To'] = email
msg['Subject'] = "Sending mail to all"
msg.attach(MIMEText(message, 'plain'))
s.send_message(msg)
del msg
s.quit()
if __name__ == '__main__':
main()

Python Email send to "Bcc" instead of "To" address

I have tried to search many times before I put down this question, but there is no answer for me.
I'm following the book "Automate Boring Stuff With Python" chapter 16.
I'm currently trying to send email to the receivers as the code format in this book.
The problem is all email I sent are put the receivers in the "Bcc" instead of "To" address which I want. How can I change from "Bcc" to "To"? Much appreciate if anyone can help me solve this problem.
Sorry for didn't attach the code. Please review.
import openpyxl, smtplib, sys
wb = openpyxl.load_workbook("listmail.xlsx")
sheet = wb.get_sheet_by_name("Sheet1")
lastCol = sheet.max_column
lastestMonth = sheet.cell(row=1, column=lastCol).value
unpaidMembers = {}
for r in range (2,sheet.max_row+1):
payment = sheet.cell(row=r,column=lastCol).value
if payment != "Paid":
name = sheet.cell(row=r, column=1).value
email = sheet.cell(row=r, column=2).value
unpaidMembers[name] = email
smtpObj = smtplib.SMTP("smtp.gmail.com",587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login("example#gmail.com", sys.argv[1])
for name, email in unpaidMembers.items():
body = "Subject: Dues Unpaid\nDear %s, \n\nThis is test"%(name)
print ("Sending email to %s...." %email)
sendmailstatus = smtpObj.sendmail("example#gmail.com",email, body)
if sendmailstatus != {}:
print ("There was a problem sending email to %s; %s" %(email, sendmailstatus))
smtpObj.quit()

Mail is going out 3 times instead of once to each address?

I have come up with something which seems weird to me and I am not sure what exactly to search for.
import smtplib, openpyxl, sys
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
wb = openpyxl.load_workbook('Book1.xlsx')
sheet = wb.get_sheet_by_name('Sheet1')
lastCol = sheet.max_column
latestMonth = sheet.cell(row=1, column=lastCol).value
recipients = []
unpaidMembers = {}
for r in range(2, sheet.max_row + 1):
payment = sheet.cell(row=r, column=lastCol).value
if payment != 'Y':
name = sheet.cell(row=r, column=1).value
email = sheet.cell(row=r, column=2).value
unpaidMembers[name] = email
recipients.append(email)
fromaddr = "xxxx#xxxx.com"
for n in recipients:
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = n
msg['Subject'] = "Hi"
body = "This is a test mail"
msg.attach(MIMEText(body, 'plain'))
filename = "xxx.pdf"
attachment = open("\\Users\xxx\xxx\xxx.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)
smtp0bj = smtplib.SMTP('smtp-mail.outlook.com', 587)
smtp0bj.ehlo()
smtp0bj.starttls()
smtp0bj.login(fromaddr, 'xxxxx')
text = msg.as_string()
smtp0bj.sendmail(fromaddr, recipients, text)
smtp0bj.quit()
I am guessing that the for-loop is being executed 3 times(there are 3 items in the list. I am at a loss about how to make it execute only once.
You basically do that :
for n in recipients: # for each recipient
smtp0bj.sendmail(fromaddr, recipients, text) # send mail to all recipients
So at each pass it sends the mail to all the recipients.
So if you have 3 recipients, they'll receive 3 mails each.
Replace with :
smtp0bj.sendmail(fromaddr, n, text)
Also I'm not sure, and can't test right now, but I believe 'to' has to be a list.
So if the above solution doesn't work, give this a shot :
smtp0bj.sendmail(fromaddr, [n], text)

Categories