2

I'm trying send email with a PDF attached. I have defined the next function:

def mail(to, subject, text, attach):
    gmail_user = "email@gmail.com"
    gmail_name = "name <email@gmail.com>"
    gmail_pwd = "password"

    msg = MIMEMultipart()

    msg['From'] = gmail_name
    msg['To'] = to
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    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, gmail_pwd)
    mailServer.sendmail(gmail_name, to, msg.as_string())
    mailServer.close()

The problem is that the console shows the following error

smtplib.SMTPServerDisconnected: Server not connected

However, if I simply replace 'msg.as_string' with "Whatever string" it works fine. So I think that this issue happens when I try attach a PDF file.

Could you help me please ?

Thanks

Luis González
  • 3,199
  • 26
  • 43

3 Answers3

3

You could also use a package specialised for writing HTML emails, showing pictures inline and easily attach files!

The package I'm referring to is yagmail and I'm the developer/maintainer.

import yagmail
yag = yagmail.SMTP(gmail_name, gmail_pwd)
yag.send('xyz@gmail.com', 'Sample subject', contents = attach)

That's all there is to it (3 lines vs 69 lines)!!

Use pip install yagmail to obtain your copy.

Contents can be a list where you also add text, but since you don't have text, you can just only have the attach filename as contents, awesome no? It reads the file, magically determines the encoding, and attached it :)

PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
1

I believe you should change this: part = MIMEBase('application', 'pdf').
Check How do I send an email with a .csv attachment using Python out for how to try to guess the file type.
Other possible issues:

  • try adding the header like this: attachment.add_header("Content-Disposition", "attachment", filename=fileToSend)
  • what Encoders are you using on this line? Encoders.encode_base64(part). I think you should be using from email import encoders and then encoders.encode_base64(part)
Community
  • 1
  • 1
gplayer
  • 1,741
  • 1
  • 14
  • 15
1

Try this-

import smtplib
import mimetypes
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


filePath = "fileName.pdf"

From = 'abc@gmail.com'
To = 'xyz@gmail.com'

msg = MIMEMultipart()
msg['From'] = From
msg['To'] = To
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = 'Sample subject'

msg.attach(MIMEText('Sample message'))

try:
    smtp = smtplib.SMTP('smtp.gmail.com:587')
    smtp.starttls()
    smtp.login('abc@gmail.com', '123456')
except:
    i = 1
else:
    i = 0

if i == 0:
    ctype, encoding = mimetypes.guess_type(filePath)
    if ctype is None or encoding is not None:
        # No guess could be made, or the file is encoded (compressed), so
        # use a generic bag-of-bits type.
        ctype = 'application/octet-stream'
    maintype, subtype = ctype.split('/', 1)
    if maintype == 'text':
        fp = open(filePath)
        # Note: we should handle calculating the charset
        part = MIMEText(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'image':
        fp = open(filePath, 'rb')
        part = MIMEImage(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'audio':
        fp = open(filePath, 'rb')
        part = MIMEAudio(fp.read(), _subtype=subtype)
        fp.close()
    else:
        fp = open(filePath, 'rb')
        part = MIMEBase(maintype, subtype)
        part.set_payload(fp.read())
        fp.close()
        # Encode the payload using Base64
        Encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment; filename="%s"' % filePath)
    msg.attach(part)
    try:
        smtp.sendmail(From, To, msg.as_string())
    except:
        print "Mail not sent"
    else:
        print "Mail sent"
    smtp.close()
else:
    print "Connection failed"

Adapted from: https://docs.python.org/2/library/email-examples.html

Swastik Padhi
  • 1,849
  • 15
  • 27