SMTPlib Attachments not received
Question:
I’ve been using code based on the snippet at http://datamakessense.com/easy-scheduled-emailing-with-python-for-typical-bi-needs/ to send PDF attachments to customers through my company’s email. We send about 100 of these at a time, through a single email address (“[email protected]”), and for each email sent, I send a BCC copy to an internal email address, as well (“[email protected]”).
From time to time (about 5 out of 100), a customer reports not getting an attachment. Sometimes it doesn’t show at all, and sometimes it shows with a red question mark. However, the BCC copy always has the attachment with no problems, and going into the sending account, the sent copy of the email always shows the attachment, also with no problem. There are no noticeable similarities in customers’ emails who have not received the attachment (such as a shared domain; in fact, most are @gmail.com). There are no exceptions or errors to report. Everything looks as though it is properly working.
This is my first time working with MIME or automating emails through Python, but the fact that it is working 98% of the time is confusing me. Are there known reasons why this might be happening? Maybe I’m not setting the type correctly? Or is there anything special I should be doing with MIME for Gmail?
Here is my code:
wdir = 'PDFs\'
filelist = []
for file in os.listdir(wdir):
if file.endswith('.pdf'):
filelist += [wdir + file] # sending all of the PDFs in a local directory
email = {}
rf = wdir + 'Reports_data.csv' # get email addresses for customers by ID (row[2])
with open(rf, 'rbU') as inf:
read = csv.reader(inf)
read.next()
for row in read:
email[row[2]] = row[3]
hfi = open('HTML\email.html', 'rb') # the HTML for the email body, itself
htmltxt = hfi.read()
hfi.close()
class Bimail:
def __init__(self, subject, recipients):
self.subject = subject
self.recipients = recipients
self.htmlbody = ''
self.sender = "[email protected]"
self.senderpass = 'password'
self.attachments = []
def send(self):
msg = MIMEMultipart('alternative')
msg['From'] = self.sender
msg['Subject'] = self.subject
msg['To'] = self.recipients[0]
msg.preamble = "preamble goes here"
if self.attachments:
self.attach(msg)
msg.attach(MIMEText(self.htmlbody, 'html'))
s = smtplib.SMTP('smtp.gmail.com:587')
s.starttls()
s.login(self.sender, self.senderpass)
s.sendmail(self.sender, self.recipients, msg.as_string())
s.quit()
def htmladd(self, html):
self.htmlbody = self.htmlbody + '<p></p>' + html
def attach(self, msg):
for f in self.attachments:
ctype, encoding = mimetypes.guess_type(f)
if ctype is None or encoding is not None:
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
fn = f.replace(wdir, '')
fp = open(f, "rb")
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
fp.close()
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=fn)
attachment.add_header('Content-ID', '<{}>'.format(f)) # or should this be format(fn)?
msg.attach(attachment)
def addattach(self, files):
self.attachments = self.attachments + files
if __name__ == '__main__':
for fi in filelist:
code = fi.split('_')[1].split('\')[1] # that "ID" for email is in the filename
addr = email[code]
mymail = Bimail(('SUBJECT HERE'), [addr, '[email protected]'])
mymail.htmladd(htmltxt)
mymail.addattach([fi])
mymail.send()
Answers:
Try out this block of code :
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email import encoders
fromaddr = "[email protected]"
password = "password"
toaddr = "[email protected]"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Report"
body = "Hi, have a look at the Report"
msg.attach(MIMEText(body, 'plain'))
filename = "Report.pdf"
attachment = open("Report.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('smtp.office365.com', 587)
server.starttls()
server.login(fromaddr, "password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
It worked for me
Sending near 100 attachments per email is not something everyone is used to do everyday, did you check there is no limitation on google SMTP server side ?
Those followings questions are relative to “Gmail sending limits in G Suite”, but in my opinion there are similar rules applied to any other gmail account.
https://support.google.com/a/answer/2956491#sendinglimitsforrelay
https://support.google.com/a/answer/166852?hl=en
Please see bellow my sendmail function:
def sendMail(to, subject, text, files=[],server="smtp.gmail.com:587",username="contact.name",password="mygmailurrentpassord"):
assert type(to)==list
assert type(files)==list
fro = "Contact Name <[email protected]>"
msg = MIMEMultipart()
msg['From'] = fro
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(fro, to, msg.as_string() )
smtp.close()
Regards
I’ve been using code based on the snippet at http://datamakessense.com/easy-scheduled-emailing-with-python-for-typical-bi-needs/ to send PDF attachments to customers through my company’s email. We send about 100 of these at a time, through a single email address (“[email protected]”), and for each email sent, I send a BCC copy to an internal email address, as well (“[email protected]”).
From time to time (about 5 out of 100), a customer reports not getting an attachment. Sometimes it doesn’t show at all, and sometimes it shows with a red question mark. However, the BCC copy always has the attachment with no problems, and going into the sending account, the sent copy of the email always shows the attachment, also with no problem. There are no noticeable similarities in customers’ emails who have not received the attachment (such as a shared domain; in fact, most are @gmail.com). There are no exceptions or errors to report. Everything looks as though it is properly working.
This is my first time working with MIME or automating emails through Python, but the fact that it is working 98% of the time is confusing me. Are there known reasons why this might be happening? Maybe I’m not setting the type correctly? Or is there anything special I should be doing with MIME for Gmail?
Here is my code:
wdir = 'PDFs\'
filelist = []
for file in os.listdir(wdir):
if file.endswith('.pdf'):
filelist += [wdir + file] # sending all of the PDFs in a local directory
email = {}
rf = wdir + 'Reports_data.csv' # get email addresses for customers by ID (row[2])
with open(rf, 'rbU') as inf:
read = csv.reader(inf)
read.next()
for row in read:
email[row[2]] = row[3]
hfi = open('HTML\email.html', 'rb') # the HTML for the email body, itself
htmltxt = hfi.read()
hfi.close()
class Bimail:
def __init__(self, subject, recipients):
self.subject = subject
self.recipients = recipients
self.htmlbody = ''
self.sender = "[email protected]"
self.senderpass = 'password'
self.attachments = []
def send(self):
msg = MIMEMultipart('alternative')
msg['From'] = self.sender
msg['Subject'] = self.subject
msg['To'] = self.recipients[0]
msg.preamble = "preamble goes here"
if self.attachments:
self.attach(msg)
msg.attach(MIMEText(self.htmlbody, 'html'))
s = smtplib.SMTP('smtp.gmail.com:587')
s.starttls()
s.login(self.sender, self.senderpass)
s.sendmail(self.sender, self.recipients, msg.as_string())
s.quit()
def htmladd(self, html):
self.htmlbody = self.htmlbody + '<p></p>' + html
def attach(self, msg):
for f in self.attachments:
ctype, encoding = mimetypes.guess_type(f)
if ctype is None or encoding is not None:
ctype = "application/octet-stream"
maintype, subtype = ctype.split("/", 1)
fn = f.replace(wdir, '')
fp = open(f, "rb")
attachment = MIMEBase(maintype, subtype)
attachment.set_payload(fp.read())
fp.close()
encoders.encode_base64(attachment)
attachment.add_header("Content-Disposition", "attachment", filename=fn)
attachment.add_header('Content-ID', '<{}>'.format(f)) # or should this be format(fn)?
msg.attach(attachment)
def addattach(self, files):
self.attachments = self.attachments + files
if __name__ == '__main__':
for fi in filelist:
code = fi.split('_')[1].split('\')[1] # that "ID" for email is in the filename
addr = email[code]
mymail = Bimail(('SUBJECT HERE'), [addr, '[email protected]'])
mymail.htmladd(htmltxt)
mymail.addattach([fi])
mymail.send()
Try out this block of code :
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email import encoders
fromaddr = "[email protected]"
password = "password"
toaddr = "[email protected]"
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Report"
body = "Hi, have a look at the Report"
msg.attach(MIMEText(body, 'plain'))
filename = "Report.pdf"
attachment = open("Report.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('smtp.office365.com', 587)
server.starttls()
server.login(fromaddr, "password")
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
It worked for me
Sending near 100 attachments per email is not something everyone is used to do everyday, did you check there is no limitation on google SMTP server side ?
Those followings questions are relative to “Gmail sending limits in G Suite”, but in my opinion there are similar rules applied to any other gmail account.
https://support.google.com/a/answer/2956491#sendinglimitsforrelay
https://support.google.com/a/answer/166852?hl=en
Please see bellow my sendmail function:
def sendMail(to, subject, text, files=[],server="smtp.gmail.com:587",username="contact.name",password="mygmailurrentpassord"):
assert type(to)==list
assert type(files)==list
fro = "Contact Name <[email protected]>"
msg = MIMEMultipart()
msg['From'] = fro
msg['To'] = COMMASPACE.join(to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach( MIMEText(text) )
for file in files:
part = MIMEBase('application', "octet-stream")
part.set_payload( open(file,"rb").read() )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'
% os.path.basename(file))
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.starttls()
smtp.login(username,password)
smtp.sendmail(fro, to, msg.as_string() )
smtp.close()
Regards