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()
Asked By: Xodarap777

||

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

Answered By: Aakash Makwana

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

Answered By: A STEFANI
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.