9

I am trying to send a csv file as an attachment via a simple function in python 3.6.

from email.message import Message
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def email():


    msg = MIMEMultipart()
    msg['Subject'] = 'test'
    msg['From'] = 'test@gmail.com'
    msg['To'] = 'testee@gmail.com'
    msg.preamble = 'preamble'

    with open("test.csv") as fp:
        record = MIMEText(fp.read())
        msg.attach(record)

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login("test@gmail.com", "password")
    server.sendmail("test@gmail.com", "testee@gmail.com", msg)
    server.quit()

Calling email() produces the error expected string or bytes-like object. Redefining server.sendmail("test@gmail.com", "testee@gmail.com", msg) as server.sendmail("atest@gmail.com", "testee@gmail.com", msg.as_string()) causes an email to be sent, but sends the csv file in the body of the email, NOT as an attachment. can anyone give me some pointers on how to send the csv file as an attachment?

MeesterTeem
  • 231
  • 4
  • 8
  • Have you tried adding a `Content-Disposition` header to your attachment? `msg.add_header('Content-Disposition', 'attachment', filename='test.csv')` – Birne94 Jan 04 '17 at 17:37
  • Is this a copy/paste error or are you actually missing a `'` on `msg['From'] = 'test@gmail.com`? – Andrew_CS Jan 04 '17 at 17:37
  • maybe [this](http://stackoverflow.com/a/3363254/3220135) is what you need? – Aaron Jan 04 '17 at 17:40
  • @Andrew_CS, Copy paste error. Thank you for catching it! I've tried adding that header, and had the same issue- the email was sent successfully, but as plaintext in the email body. http://prntscr.com/drhazy – MeesterTeem Jan 04 '17 at 17:46
  • Possible duplicate: http://stackoverflow.com/questions/3362600/how-to-send-email-attachments-with-python – Robᵩ Jan 04 '17 at 17:49
  • Thank you all for the help. @Robᵩ 's excellent answer works perfectly. – MeesterTeem Jan 04 '17 at 17:57

1 Answers1

10

1) You should use msg.as_string() if you call smtplib.SMTP.sendmail(). Alternatively, if you have Python 3.2 or newer, you can use server.send_message(msg).

2) You should add a body to your message. By design no one ever sees the preamble.

3) You should use content-disposition: attachment to indicate which parts are attachments and which are inline.

Try this:

def email():


    msg = MIMEMultipart()
    msg['Subject'] = 'test'
    msg['From'] = 'XXX'
    msg['To'] = 'XXX'
    msg.preamble = 'preamble'

    body = MIMEText("This is the body of the message")
    msg.attach(body)

    with open("test.csv") as fp:
        record = MIMEText(fp.read())
        record['Content-Disposition'] = 'attachment; filename="test.csv"'
        msg.attach(record)

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login("XXX", "XXX")
    server.sendmail("XXX", "XXX", msg.as_string())
    server.quit()
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • This worked perfectly! Thank you so much. I'd tried a file header, but i attached it incorrectly. – MeesterTeem Jan 04 '17 at 17:57
  • So, do u know a way to send html with this? – Murilo Melo Aug 03 '21 at 16:32
  • 1
    This is working. "If your gmail is secured by Two-Factor Authentication, you must first generate an application specific password https://security.google.com/settings/security/apppasswords?pli=1 then use that app-password for in the above example code (this is very important because then you aren't writing your password down anywhere in cleartext AND you can revoke the app-password at any time)". This is taken from this link: https://stackoverflow.com/a/12424439/1944314 comment section below. – Alper Oct 06 '22 at 19:14