I am writing an automation Python Script. My intention is to email multiple unique attachments to multiple unique recipients. For example l have 1000 unique statements that must be emailed to 1000 unique clients. I want my Python script to be able to pick an attachment automatically and send it to the right recipient!
I have created the script and that creates the pdf attachments and name them after each email address of recipients so that l can use the names to pick the attachment and match that with the email of the recipient.
It Picks attachment perfectly BUT the problems it keeps incrementing attachment to users in each iteration..
#1.READING FILE NAMES WHICH ARE EMAIL ADDRESS FOR RECEPIENTS
import os, fnmatch
filePath = "C:/Users/DAdmin/Pictures/"
def readFiles(path):
fileNames =fnmatch.filter(os.listdir(path), '*.pdf')
i=0
pdfFilesNamesOnly=[]
while i < len(fileNames):
s =fileNames[i]
removeThePdfExtension= s[0:-4]
pdfFilesNamesOnly.append(removeThePdfExtension)
i+=1
return pdfFilesNamesOnly
-----------------------------------------------------------
#2.SENDING AN EMAIL WITH UNIQUE ATTACHMENT TO MULTIPLE UNIQUE RECEPIENTS
import smtplib
import mimetypes
from optparse import OptionParser
from email.mime.multipart import MIMEMultipart
from email import encoders
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
import os,fnmatch
from readFileNames import readFiles
filePath = "C:/Users/DAdmin/Pictures/"
listOfEmails= readFiles(filePath)# Files are named after emails
def sendEmails(listOfFiNames): #sends the email
email = 'goddietshe#gmail.com' # Your email
password = '#####' # Your email account password
send_to_list = listOfEmails# From the file names
#creating a multipart object
subject ="MONTHLY STATEMENTS"
mg = MIMEMultipart('alternative')
mg['From'] = email
mg['To'] = ",".join(send_to_list)
mg['Subject'] = subject
mg.attach(MIMEText("Please receive your monthly statement",'plain'))
# Attaching a file now before emailing. (Where l have a problem)
for i in listOfEmails:
if i in send_to_list:
newFile = (i+'.pdf') # create the name of the attachment to email using the name(which is the email) and will be used to pick the attachment
with open(newFile,'rb') as attachment:
part = MIMEBase('application','x- pdf')
part.set_payload(attachment.read())
attachment.close()
encoders.encode_base64(part)
part.add_header('Content- Disposition','attachment; filename="%s"' % newFile )
mg.attach(part)
text =mg.as_string() # converting the message obj to a string/text obj
server = smtplib.SMTP('smtp.gmail.com', 587) # Connect to the server
server.starttls() # Use TLS
server.login(email, password) # Login to the email server
# this is where it is emailing stuff
server.sendmail(email, i , text) # Send the email
server.quit() # Logout of the email server
print("The mail was sent")
#print("Failed ")
sendEmails(listOfFiNames)
I expect it to email each unique attachment to each unique recipient who are 1000 automatically
You reuse mg (message), using only attach, so your attachments pile up. You need to substitute the whole previous content with new content using set_payload because there is no "remove" method.
In doing this, you have to remember to re-add the text which you set before the loop:
mg.attach(MIMEText("Please receive your monthly statement",'plain'))
for i in listOfEmails:
because by using set_payload you lose all previous parts you attached. I'd just save this as a variable and then add it in the loop.
Moreover:
mg['To'] = ",".join(send_to_list)
This line makes all messages send to all people. You need to move this part to the loop as well, setting only one email address at once.
EDIT Applying those changes:
def sendEmails(): #sends the email
email = 'goddietshe#gmail.com' # Your email
password = '#####' # Your email account password
#creating a multipart object
subject ="MONTHLY STATEMENTS"
mg = MIMEMultipart('alternative')
mg['From'] = email
# mg['To'] = ",".join(listOfEmails) # NO!
mg['Subject'] = subject
text_content = MIMEText("Please receive your monthly statement",'plain')) #safe it for later, rather than attach it - we'll have to re-attach it every loop run
for i in listOfEmails:
if i in send_to_list:
newFile = (i+'.pdf') # create the name of the attachment to email using the name(which is the email) and will be used to pick the attachment
with open(newFile,'rb') as attachment:
part = MIMEBase('application','x- pdf')
part.set_payload(attachment.read())
attachment.close()
encoders.encode_base64(part)
part.add_header('Content- Disposition','attachment; filename="%s"' % newFile )
mg.set_payload(text_content) #change the whole content into text only (==remove previous attachment)
mg.attach(part) #keep this - new attachment
mg["To"] = i # send the email to the current recipient only!
text =mg.as_string() # converting the message obj to a string/text obj
server = smtplib.SMTP('smtp.gmail.com', 587) # Connect to the server
server.starttls() # Use TLS
server.login(email, password) # Login to the email server
# this is where it is emailing stuff
server.sendmail(email, i , text) # Send the email
server.quit() # Logout of the email server
print("The mail was sent")
**Works very fine like this. Thanks #h4z3**
def sendEmail():
email = 'goddietshetu#gmail.com' # Your email
password = '####' # Your email account password
subject ="MONTHLY STATEMENTS"
#creating a multipart object
mg = MIMEMultipart('alternative')
mg['From'] = email
mg['Subject'] = subject
# attaching a file now
listOfEmails = readFileNames(filePath)
for i in listOfEmails:
attachment =open(i+'.pdf','rb')
part = MIMEBase('application','octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition',f"attachment; filename= {i}.pdf")
mg.set_payload(mg.attach(MIMEText("",'plain')))
mg.attach(MIMEText("Please receive your monthly statement",'plain'))
mg.attach(part)
mg['To'] = i
text =mg.as_string() # converting the message obj to a string/text obj
server = smtplib.SMTP('smtp.gmail.com', 587) # Connect to the server
server.starttls() # Use TLS
server.login(email, password) # Login to the email server
server.sendmail(email, i , text) # Send the email
server.quit() # Logout of the email serv
print("The mail was sent")
sendEmail()
Related
How can I send multiple mails with a hidden recipient?
I can currently send mails, but people who receive it can see the recipient.
My code looks like this:
import smtplib
from email.message import EmailMessage
email_subject = "Good morning"
sender_email_address = "user#outlook.com"
receivers_email_address = ['reciever1#gmail.com', 'reciever2#gmail.com']
email_smtp = "smtp.office365.com"
email_password = "MyPassword"
# Create an email message object
message = EmailMessage()
# Configure email headers
message['Subject'] = email_subject
message['From'] = sender_email_address
message['To'] = ", ".join(receivers_email_address)
# Read file containing html
with open('message.html', 'r') as file:
file_content = file.read()
# Add message content as html type
message.set_content(file_content, subtype='html')
# Set smtp server and port
server = smtplib.SMTP(email_smtp, '587')
# Identify this client to the SMTP server
server.ehlo()
# Secure the SMTP connection
server.starttls()
# Login to email account
server.login(sender_email_address, email_password)
# Send email
server.send_message(message)
# Close connection to server
server.quit()
You don't need to send multiple messages. Just don't put the recipients explicitly in the headers.
The following implements this by putting the recipients in the Bcc: header.
import smtplib
from email.message import EmailMessage
email_subject = "Good morning"
sender_email_address = "user#outlook.com"
receivers_email_address = ['reciever1#gmail.com', 'reciever2#gmail.com']
email_smtp = "smtp.office365.com"
email_password = "MyPassword"
message = EmailMessage()
message['Subject'] = email_subject
message['From'] = sender_email_address
# The message needs to have a To: header
# - putting yourself is an old convention
message['To'] = sender_email_address
message['Bcc'] = ",".join(receivers_email_address)
with open('message.html', 'r') as file:
file_content = file.read()
message.set_content(file_content, subtype='html')
with smtplib.SMTP(email_smtp, '587') as server:
server.ehlo()
server.starttls()
server.login(sender_email_address, email_password)
server.send_message(message)
server.quit()
Of course, if you really need to To: header to indicate the actual recipient, you will need to generate a unique message for each of them.
This relies on the SMTP server to read and strip off the Bcc: header. If you can't rely on yours to do that, you can explicitly use the legacy sendmail method of the smtplib module, which lets you explicitly pass in the list of actual recipients separately from the message. Then you can also avoid the pesky copy to yourself.
To briefly recap, SMTP doesn't really care what's in the To: or Cc: headers; the actual list of recipients is communicated separately, before you submit the actual message. This is called the SMTP envelope.
I made a loop to send individually. Instead of sending it to multiple people in a group.
import smtplib
from email.message import EmailMessage
email_subject = "Good morning"
sender_email_address = "user#outlook.com"
receivers_email_address = ['reciever1#gmail.com', 'reciever2#gmail.com']
email_smtp = "smtp.office365.com"
email_password = "MyPassword"
# Read file containing html
with open('message.html', 'r') as file:
file_content = file.read()
# Set smtp server and port
server = smtplib.SMTP(email_smtp, '587')
# Identify this client to the SMTP server
server.ehlo()
# Secure the SMTP connection
server.starttls()
# Login to email account
server.login(sender_email_address, email_password)
# Send email
for receiver in receivers_email_address:
# Create an email message object
message = EmailMessage()
message['Subject'] = email_subject
message['From'] = sender_email_address
message['To'] = receiver
# Add message content as html type
message.set_content(file_content, subtype='html')
server.send_message(message)
# Close connection to server
server.quit()
I have an output of df['sentiments'] as sentiment output of twitter tweets. I want to mail that sentiment output over email to another person automatically.
Store it in a file using df['sentiments'].to_csv('sentiment.csv'). And send the file sentiment.csv via mail.
More details about to_csv function can be found here in the official docs.
EDIT: Expanding the answer for the sake of making it less troublesome. Credits for this part
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
mail_content = '''Sample message'''
#The mail addresses and password
sender_address = 'sender#gmail.com'
sender_pass = 'xxxxxxxxxxx'
receiver_address = 'receiver#gmail.com'
#Setup the MIME
message = MIMEMultipart()
message['From'] = sender_address
message['To'] = receiver_address
message['Subject'] = 'A test mail sent by Python. It has an attachment.'
#The body and the attachments for the mail
message.attach(MIMEText(mail_content, 'plain'))
filename = "database.txt" #- Attach the sentiment.csv and metadata file here
# 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)
#Create SMTP session for sending the mail
session = smtplib.SMTP('smtp.gmail.com', 587) #use gmail with port
session.ehlo()
session.starttls() #enable security
session.login(sender_address, sender_pass) #login with mail_id and password
text = message.as_string()
session.sendmail(sender_address, receiver_address, text)
session.quit()
print('Mail Sent')
If you get an error as follows:
(535, b'5.7.8 Username and Password not accepted. Learn more at\n5.7.8 https://support.google.com/mail/?p=BadCredentials y186sm1525057pfy.66 - gsmtp')
Follow this thread
You can use the python built in library smtplib:
https://docs.python.org/3/library/smtplib.html to send emails.
You can use, for example the GMAIL mail server to send it.
https://www.tutorialspoint.com/send-mail-from-your-gmail-account-using-python
I found a small program that will send my phone a text message through my gmail, but when I send the text it adds on "[Attachment(s) removed]", is there any way to remove that?
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
email = "Your Email"
pas = "Your Pass"
sms_gateway = 'number#tmomail.net'
# The server we use to send emails in our case it will be gmail but every email provider has a different smtp
# and port is also provided by the email provider.
smtp = "smtp.gmail.com"
port = 587
# This will start our email server
server = smtplib.SMTP(smtp,port)
# Starting the server
server.starttls()
# Now we need to login
server.login(email,pas)
# Now we use the MIME module to structure our message.
msg = MIMEMultipart()
msg['From'] = email
msg['To'] = sms_gateway
# Make sure you add a new line in the subject
msg['Subject'] = "You can insert anything\n"
# Make sure you also add new lines to your body
body = "You can insert message here\n"
# and then attach that body furthermore you can also send html content.
msg.attach(MIMEText(body, 'plain'))
sms = msg.as_string()
server.sendmail(email,sms_gateway,sms)
# lastly quit the server
server.quit()
When you are doing the server.sendmail step just send the body string. So instead it would be:
import smtplib
email = "Your Email"
pas = "Your Pass"
sms_gateway = 'number#tmomail.net'
smtp = "smtp.gmail.com"
port = 587
# This will start our email server
server = smtplib.SMTP(smtp,port)
# Starting the server
server.starttls()
# Now we need to login
server.login(email,pas)
body = "Yo, im done."
server.sendmail(email,sms_gateway,body)
# lastly quit the server
server.quit()
I have a running Angular2 app which has currently been hosted on Firebase.
And then I have a python (2.7) code using which a user can mail some file (present locally on his computer) to some person, both having gmail accounts.
I tested this code and it works fine on my laptop.
My question is, how can I include this python code with my existing Angular2 Web application so that it runs the same way as it runs on a computer, and sends a mail with some attachments?
Here is my Python code :
# Python code to illustrate Sending mail with attachments
# from your Gmail account
# libraries to be imported
import os
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
fromaddr = "sender#gmail.com"
toaddr = "recipient#gmail.com"
# instance of MIMEMultipart
msg = MIMEMultipart()
# storing the senders email address
msg['From'] = fromaddr
# storing the receivers email address
msg['To'] = toaddr
# storing the subject
msg['Subject'] = "Trial Attachments"
# string to store the body of the mail
body = "Just checking if Images would go"
# attach the body with the msg instance
msg.attach(MIMEText(body, 'plain'))
# open the file to be sent
#filename = "tash.png"
folder = os.listdir("/path/to-some/folder/")
for f in folder:
filename = f
attachment = open("/path/to-some/folder/%s" %(f), "rb")
# instance of MIMEBase and named as p
p = MIMEBase('application', 'octet-stream')
# To change the payload into encoded form
p.set_payload((attachment).read())
# encode into base64
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
# attach the instance 'p' to instance 'msg'
msg.attach(p)
# creates SMTP session
s = smtplib.SMTP('smtp.gmail.com', 587)
# start TLS for security
s.starttls()
# Authentication
s.login(fromaddr, "######")
# Converts the Multipart msg into a string
text = msg.as_string()
# sending the mail
try:
s.sendmail(fromaddr, toaddr, text)
print "Successfully sent email"
except:
print "Failed to send mail"
# terminating the session
s.quit()
After replacing headers like from,to,sub i am able to forward mail to another email address.
But how can I forward mail by adding more attachments and more text or html content.
As we see in the gmail, new contents should be displayed before the forwrded message content. Any idea on how could we achieve this?
Forwarded mail can be multipart or not.
But since we add new content it will be multipart
I have tried the code below
# open IMAP connection and fetch message with id msgid
# store message data in email_data
client = imaplib.IMAP4_SSL(imap_host,993)
client.login(user, passwd)
client.select('INBOX')
result, data = client.uid('fetch', msg_id, "(RFC822)")
client.close()
client.logout()
# create a Message instance from the email data
message = email.message_from_string(data[0][1])
# replace headers (could do other processing here)
message.replace_header("From", from_addr)
message.replace_header("To", to_addr)
message.replace_header("Subject", "Fwd:"+ message["Subject"].replace("FWD: ", "").replace("Fwd: ","" ))
# open authenticated SMTP connection and send message with
# specified envelope from and to addresses
smtp = smtplib.SMTP_SSL(smtp_host, smtp_port)
smtp.login(user, passwd)
smtp.sendmail(from_addr, to_addr, message.as_string())
smtp.quit()
I was able to achieve this using the email package, attaching the original email as a part:
from email.message import Message
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.message import MIMEMessage
from email import message_from_bytes
raw_email = get_raw_email() # get the original email from wherever
original_email = message_from_bytes(raw_email)
part1 = MIMEText("This is new content")
part2 = MIMEMessage(original_email)
new_email = MIMEMultipart()
new_email['Subject'] = "My subject"
new_email['From'] = 'abc#xyz.com'
new_email['To'] = '123#456.com'
new_email.attach(part1)
new_email.attach(part2)