9

I have the following code which works fine, but it doesn't send the attachment files.

import smtplib
import os
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.MIMEBase import MIMEBase
from email import Encoders

msg=MIMEMultipart()

def mymail(address,body,format,mylist=None):

    msg['To']=address
    msg['From']='ggous1@gmail.com'
    if format=='txt':
        text_msg=MIMEText(body,'plain')
    elif format=='html':
        text_msg=MIMEText(body,'html')
    msg.attach(text_msg)
    if mylist is not None:
        mylist=[]
        fn=[]
        for f in range(len(mylist)):
            direct=os.getcwd()
            os.chdir(direct)
            part=MIMEBase('application','octet-stream')
            part.set_payload(open(mylist[f],'rb').read())
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(mylist[f])) 
            fn.append(part)
            msg.attach(fn)

    srv=smtplib.SMTP('smtp.gmail.com')
    srv.set_debuglevel(1)
    srv.ehlo()
    srv.starttls()
    srv.ehlo()
    srv.login('username','pass')
    srv.sendmail(msg['From'],msg['To'],msg.as_string())
    srv.quit()

if __name__=="__main__":
    address=raw_input('Enter an address to send email in the form "name@host.com" ')
    body=raw_input('Enter the contents of the email')
    format=raw_input('The format is txt or html?')
    question=raw_input('Do you have any files to attach?Yes or No?')
    mylist=[]
    if question=='Yes' or question=='yes':
        fn=raw_input('Enter filename')
        mylist.append(fn)

    mymail(address,body,format,mylist)

Am I not using MIMEBase right, or do I have an error in my code?

UPDATE------------------------

 if mylist is not None:
        mylist=[]
        fn=[]
        for f in range(len(mylist)):
            direct=os.getcwd()
            os.chdir(direct)
            fn[f]=open(mylist[f],'r')             
            part=msg.attach(MIMEApplication(fn[f]))
            mylist.append(part)
George
  • 5,808
  • 15
  • 83
  • 160
  • Also, you could (should) just check **'if mylist:'** instead of an explicit comparison. **'if mylist:'** will return **False** if it is 'None' or an empty list, dictionary, string, etc. Also consider using **"if question.lower() == 'yes':"** – MrWonderful Jan 24 '14 at 20:29

1 Answers1

23

I would recommend to use MIMEApplication instead for the attachment. You also do not need to do all the payload encoding manually since that is already done automatically. This example works for me:

from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.utils import formataddr
from email.utils import make_msgid
from email.utils import formatdate

email = MIMEMultipart()
email['From'] = formataddr(('Jane Doe', 'jane@example.com'))
email['Subject'] = u'Test email'
email['Message-Id'] = make_msgid()
email['Date'] = formatdate(localtime=True)
email.attach(MIMEText(u'This is your email contents.'))
email.attach(MIMEApplication('your binary data'))
print email.as_string()

Note that I'm also taking care to set a proper Date and Message-Id header here.

Applying that to your code (and doing a few small cleanups) I get the following working code:

import smtplib
import os
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
from email.utils import make_msgid
from email.utils import formatdate


def make_mail(address,body,format,mylist=[]):
    msg = MIMEMultipart()
    msg['To'] = address
    msg['From'] = 'ggous1@gmail.com'
    msg['Message-Id'] = make_msgid()
    msg['Date'] = formatdate(localtime=True)
    msg.attach(MIMEText(body, 'plain' if format == 'txt' else 'html'))
    for filename in mylist:
        part = MIMEApplication(open(filename).read())
        part.add_header('Content-Disposition',
                'attachment; filename="%s"' % os.path.basename(filename))
        msg.attach(part)
    return msg    

def send_mail(msg):
    srv = smtplib.SMTP('smtp.gmail.com')
    srv.set_debuglevel(1)
    srv.ehlo()
    srv.starttls()
    srv.ehlo()
    srv.login('username','pass')
    srv.sendmail(msg['From'], msg['To'], msg.as_string())
    srv.quit()

if __name__=="__main__":
    address=raw_input('Enter an address to send email in the form "name@host.com" ')
    body=raw_input('Enter the contents of the email')
    format=raw_input('The format is txt or html?')
    question=raw_input('Do you have any files to attach?Yes or No?')
    mylist=[]
    if question=='Yes' or question=='yes':
        fn=raw_input('Enter filename')
        mylist.append(fn)

    msg = make_mail(address,body,format,mylist)
    send_mail(msg)
Wichert Akkerman
  • 4,918
  • 2
  • 23
  • 30