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