I was trying to send around 10+ emails (each has an Excel file attached) consecutively by invoking the below Python function send_email(), which is based on the sample code shared by the tutorials on the web.
Somehow I found that though the 10+ emails are sent without errors/exceptions, occasionally some of the emails are not recipeved by the recipients. I checked the Sent box of the specified sender email account, for the emails that weren't received by the recipients, they are not in the sender's Sent box either.
I speculated that it could be due to those consecutive invocations of send_email() overflooded the SMTP server (but not sure) so I added 1 sec delay between the invocation (as specified below). However, the issue still happens occasionally. Now I'm trying to increase the delay from 1sec to 10sec.
Please kindly advise if my speculation is in the right direction and if there is anything I need to do to better pinpoint the root cause. Thanks a lot.
My code is as follows:
(a) Invoking send_email() consecutively in a loop. For each loop assign the corresponding email recipients, subject, message, and Excel attachment as the inputs.
(b) To add delays in between send_email() calls, time.sleep(1) is invoked to add 1 sec delay in the hope of not to overflow the SMTP server.
(c) The code of send_email() is as follows:
#Email the generated Excel file out
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os.path
def send_email(email_recipients, email_subject, email_message, attachment_location = ''):
email_sender = 'xxx' #xxx is the sender's email address
msg = MIMEMultipart()
msg['From'] = email_sender
msg['To'] = ", ".join(email_recipients)
msg['Subject'] = email_subject
msg.attach(MIMEText(email_message, 'plain'))
if attachment_location != '':
filename = os.path.basename(attachment_location)
attachment = open(attachment_location, "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)
try:
mailserver = smtplib.SMTP('smtp.office365.com', 587)
mailserver.ehlo()
mailserver.starttls()
mailserver.login('xx', 'xxxx') # xx and xxxx are the credentials for the smtp server
text = msg.as_string()
mailserver.sendmail(email_sender, email_recipients, text)
print('email sent')
except Exception as e:
print(e)
print("SMPT server connection error")
finally:
mailserver.quit()
return True
Related
Using the email and smtp libraries, I have developed a script that automatically sends mail via outlook's smtp server.
I enter the content of the mail and after the content is written I want to send the picture at the bottom.
But it sends the picture not at the bottom as I want it, but at the top of the mail content.
Example mail ( This is only image ) : https://ibb.co/d5HFwRG
My code:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
def send_mail(gender, messages, subject):
global msg
try:
msg = MIMEMultipart()
s = smtplib.SMTP(host="SMTP.office365.com", port=587)
s.starttls()
s.login(mail, password)
msg['From'] = mail
msg['To'] = example#outlook.com
msg['Subject'] = messages
msg.attach(MIMEText(message, 'plain', 'utf-8'))
attachment = open("image.jpg", "rb")
p = MIMEBase('application', 'octet-stream')
p.set_payload((attachment).read())
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment; filename= %s" % image)
msg.attach(p)
s.send_message(msg)
del msg
except Exception as e:
print(e)
My code is actually much more complex, but I just showed you the function I use to send mail.
I had to change the names of some variables while adding them here, so the above code may not work for you, you need to edit it.
How can I get that picture sent in the Mail to the bottom?
I want to make a python script that sends an email with an attachment (txt) every 30 minutes. Here is my code to send the email with the attachment. It's working without any problems. However, I need help to figure out how to send this on a time schedule.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import os.path
email = 'myaddress#gmail.com'
password = 'password'
send_to_email = 'sentoaddreess#gmail.com'
subject = 'This is the subject'
message = 'This is my message'
file_location = 'C:\\Users\\You\\Desktop\\attach.txt'
msg = MIMEMultipart()
msg['From'] = email
msg['To'] = send_to_email
msg['Subject'] = subject
msg.attach(MIMEText(message, 'plain'))
filename = os.path.basename(file_location)
attachment = open(file_location, "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('smtp.gmail.com', 587)
server.starttls()
server.login(email, password)
text = msg.as_string()
server.sendmail(email, send_to_email, text)
server.quit()
Two options for you
You can look into scheduling your python script to run at a certain time interval. This means, each script run would send one email, and you would stop the automated task rather than stopping the script when you want the emails to stop. If you're running Windows OS, they have a built in application called Task Scheduler to manage this for you.
Option two is to use the time.sleep() function. This method would mean the script would continue to run and shoot off an email every 30 minutes. The script would have to be stopped when you want the emails to stop.
import time
while True:
{insert your email send code here}
time.sleep(60*30) # this is in seconds, so 60 seconds x 30 mins
I have put together a function send_email [1] to send emails with support for plain-text and html messages. It works well, but I have an issue I don't quite know how to debug. My system has sendmail as its MTA.
The function is called in a for loop, as follows:
for data in data_set:
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, "fixed#email.address")
In the debug output of smtplib [1] I see that all calls to send_email completed successfully. The weird behavior is:
If the message is "short" (I tested with a single line), all sent messages actually arrive to fixed#email.address
If the message is "not short" (that is, the multiple lines I generate with the real process_data function), only the first email does arrive, while the others don't, even though the debug output of smtplib in [1] reports success for each and all of the emails.
If the message is equally "not short" but the destination address is different for each message, then all messages arrive to their intended destinations.
For the latter case, the for loop would look like:
addresses = ["fixed#email.address", "fixed.2#email.address", ...]
for data, addr in zip(data_set, addresses):
subject, message = process(data) # Irrelevant stuff
send_email(subject, message, addr)
The intended behavior is of course different addresses for different data, but I'm concerned that not understanding why this happens might bite me in an unexpected way later on.
[1] My send mail function:
import smtplib
import socket
import getpass
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def send_email (subject, message, to, reply_to='', cc='', html_message=''):
COMMASPACE = ", "
user, host = get_user_and_host_names()
sender = '%s#%s' % (user, host)
receivers = make_address_list(to)
copies = make_address_list(cc)
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = COMMASPACE.join(receivers)
if reply_to:
msg.add_header('Reply-to', reply_to)
if len(copies):
msg.add_header('CC', COMMASPACE.join(copies))
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
if message:
msg.attach( MIMEText(message, 'plain'))
if html_message:
msg.attach( MIMEText(html_message, 'html'))
smtpObj = smtplib.SMTP('localhost')
smtpObj.set_debuglevel(1)
smtpObj.sendmail(sender, receivers, msg.as_string())
smtpObj.quit()
print "\nSuccessfully sent email to:", COMMASPACE.join(receivers)
def get_user_and_host_names():
user = getpass.getuser()
host = socket.gethostname()
return user, host
def make_address_list (addresses):
if isinstance(addresses, str):
receivers = addresses.replace(' ','').split(',')
elif isinstance(addresses, list):
receivers = addresses
return receivers
A working solution I had for sending email:
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import smtplib
class EMail(object):
""" Class defines method to send email
"""
def __init__(self, mailFrom, server, usrname, password, files, debug=False):
self.debug = debug
self.mailFrom = mailFrom
self.smtpserver = server
self.EMAIL_PORT = 587
self.usrname = usrname
self.password = password
def sendMessage(self, subject, msgContent, files, mailto):
""" Send the email message
Args:
subject(string): subject for the email
msgContent(string): email message Content
files(List): list of files to be attached
mailto(string): email address to be sent to
"""
msg = self.prepareMail(subject, msgContent, files, mailto)
# connect to server and send email
server=smtplib.SMTP(self.smtpserver, port=self.EMAIL_PORT)
server.ehlo()
# use encrypted SSL mode
server.starttls()
# to make starttls work
server.ehlo()
server.login(self.usrname, self.password)
server.set_debuglevel(self.debug)
try:
failed = server.sendmail(self.mailFrom, mailto, msg.as_string())
except Exception as er:
print er
finally:
server.quit()
def prepareMail(self, subject, msgHTML, attachments, mailto):
""" Prepare the email to send
Args:
subject(string): subject of the email.
msgHTML(string): HTML formatted email message Content.
attachments(List): list of file paths to be attached with email.
"""
msg = MIMEMultipart()
msg['From'] = self.mailFrom
msg['To'] = mailto
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
#the Body message
msg.attach(MIMEText(msgHTML, 'html'))
msg.attach(MIMEText("Add signature here"))
if attachments:
for phile in attachments:
# we could check for MIMETypes here
part = MIMEBase('application',"octet-stream")
part.set_payload(open(phile, "rb").read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(phile))
msg.attach(part)
return msg
I hope this helps.
My Working solution to format your list in this manner (after many hours of experiment):
["firstemail#mail.com", "secondmail#mail.com", "thirdmail#email.com"]
I used:
to_address = list(str(self.to_address_list).split(","))
to convert my QString into string then into list with splitting with a ","
In my case COMMASPACE was not working, because on splitting a space was already added by default.
Edit question for new issue
I was able to get Email But it was delay from server side.**
I am writing very small application for sending email with attachment of excel file in python. it contain multiple worksheet and each worksheet contain graph. I received email but it looks like File was corrupted.
is it possible to attach Excel which contain graph( size also upto 2MB)
# -*- coding: iso-8859-1 -*-
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from smtplib import SMTP
import smtplib,email,email.encoders,email.mime.text,email.mime.base
msg = MIMEMultipart()
msg['Subject'] = 'Email From Python Abhishek'
msg['From'] = 'xyz.com'
msg['To'] = 'abc.com'
fileMsg = email.mime.base.MIMEBase('application','vnd.ms-excel')
fileMsg.set_payload(file('Final.xlsx').read())
email.encoders.encode_base64(fileMsg)
fileMsg.add_header('Content-Disposition','attachment;filename=Final.xlsx')
msg.attach(fileMsg)
smtp = SMTP("email exchange server",25)
#(I was able to connect with exchange server using Telnet http://www.exchangeinbox.com/article.aspx?i=93)
# Start the server:
smtp.ehlo()
I have commented below code as per one internet posting. it suggest that if you
are sending internal Email you may not require login and password.I also do not
want to write password as it is violate company policy
if I remove comment from line. it give me error for bad authentication.
#smtp.login("abc", "password")
smtp.sendmail(msg['From'],msg['To'],msg.as_string())
#server.quit()
Here is a script that I have used for sending email from a gmail account, it should work for others in theory, but I have only tested with gmail. You can call it from the command line passing in the arguements listed in main or you can call the mail function directly from another Python module:
#!/usr/bin/python
# currently set up and tested on gmail only
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os, sys, base64
def mail(gmail_user, enc_pwd, to, subject, body, attach):
msg = MIMEMultipart()
msg['From'] = gmail_user
msg['To'] = to
msg['Subject'] = subject
msg.attach(MIMEText(body, 'html'))
if attach:
part = MIMEBase('application', 'octet-stream')
part.set_payload(open(attach, 'rb').read())
Encoders.encode_base64(part)
part.add_header('Content-Disposition',
'attachment; filename="%s"' % os.path.basename(attach))
msg.attach(part)
mailServer = smtplib.SMTP("smtp.gmail.com", 587)
mailServer.ehlo()
mailServer.starttls()
mailServer.ehlo()
mailServer.login(gmail_user, base64.b64decode(enc_pwd))
mailServer.sendmail(gmail_user, to, msg.as_string())
mailServer.close()
def main():
if len(sys.argv) <6:
print "Usage: send_email.py <from> <enc_pwd> <to> <subject> <body> " \
"[<attachments>]"
print "Note: Email is being sent in html mode, so any newlines should " \
"be sent as <br/>"
if len(sys.argv) > 1:
print "\nThe following arguements were received:"
for i in sys.argv:
print i
else:
gmail_user = sys.argv[1]
gmail_pwd = sys.argv[2]
to = sys.argv[3]
subject = sys.argv[4]
body = sys.argv[5]
attach = None
if len(sys.argv) >= 7:
attach = sys.argv[6]
mail(gmail_user, gmail_pwd, to, subject, body, attach)
if __name__ == '__main__':
main()
Let me know if you have any questions
I am developing an application using python where I need to send a file through mail. I wrote a program to send the mail but dont know there's something wrong. The code is posted below. Please any one help me with this smtp library. Is there's anything i m missing? And also can someone please tell me what will be the host in smtp! I am using smtp.gmail.com.
Also can any one tell me how can i email a file (.csv file). Thanks for the help!
#!/usr/bin/python
import smtplib
sender = 'someone#yahoo.com'
receivers = ['someone#yahoo.com']
message = """From: From Person <someone#yahoo.com>
To: To Person <someone#yahoo.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
try:
smtpObj = smtplib.SMTP('smtp.gmail.com')
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except:
print "Error: unable to send email"
You aren't logging in. There are also a couple reasons you might not make it through including blocking by your ISP, gmail bouncing you if it can't get a reverse DNS on you, etc.
try:
smtpObj = smtplib.SMTP('smtp.gmail.com', 587) # or 465
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login(account, password)
smtpObj.sendmail(sender, receivers, message)
print "Successfully sent email"
except:
print "Error: unable to send email"
I just noticed your request to be able to attach a file. That changes things since now you need to deal with encoding. Still not that tough to follow though I don't think.
import os
import email
import email.encoders
import email.mime.text
import smtplib
# message/email details
my_email = 'myemail#gmail.com'
my_passw = 'asecret!'
recipients = ['jack#gmail.com', 'jill#gmail.com']
subject = 'This is an email'
message = 'This is the body of the email.'
file_name = 'C:\\temp\\test.txt'
# build the message
msg = email.MIMEMultipart.MIMEMultipart()
msg['From'] = my_email
msg['To'] = ', '.join(recipients)
msg['Date'] = email.Utils.formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(email.MIMEText.MIMEText(message))
# build the attachment
att = email.MIMEBase.MIMEBase('application', 'octet-stream')
att.set_payload(open(file_name, 'rb').read())
email.Encoders.encode_base64(att)
att.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file_name))
msg.attach(att)
# send the message
srv = smtplib.SMTP('smtp.gmail.com', 587)
srv.ehlo()
srv.starttls()
srv.login(my_email, my_passw)
srv.sendmail(my_email, recipients, msg.as_string())