Search code examples
pythoncsvemailsmtpmime

How to attach CSV file with MIME/SMTP and email?


I’m attempting to attach a CSV file and email it.

Currently, I am doing the following but it simply attaches an empty CSV file, rather than attaching the CSV file I have in the same directory:

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.utils import COMMASPACE
from email import encoders


def email_attachment():
    SUBJECT = 'Subject string'

    msg = MIMEMultipart()
    msg['From'] = 'my_email@yahoo.com'
    msg['To'] = COMMASPACE.join(['recepient_email@gmail.com'])
    msg['Subject'] = SUBJECT

    part = MIMEBase('application', "octet-stream")
    #    I have a CSV file named `attachthisfile.csv` in the same directory that I'd like to attach and email
    part.set_payload(open("./attachthisfile.csv", "rb").read())
    encoders.encode_base64(part)

    part.add_header('Content-Disposition', 'attachment', filename='attachthisfile.csv')

    msg.attach(part)

    smtpObj = smtplib.SMTP('smtp.mail.yahoo.com', 587)
    smtpObj.ehlo()
    smtpObj.starttls()
    smtpObj.login('my_email@yahoo.com', 'myemailpassword')
    smtpObj.sendmail('my_email@yahoo.com', 'recepient_email@gmail.com', msg.as_string())

    smtpObj.quit()

So my question is, what could I be doing wrong? How can I attach the CSV file in the same directory and email, rather than creating an empty CSV file and naming it the same, and emailing?


Solution

  • The issue seems to be with this line:

    part.add_header('Content-Disposition', 'attachment; filename=“attachthisfile.csv"')
    

    It contains a Non-ASCII character '\xe2' after filename=. It's the old ascii encoding problem, in this case it's: vs "

    As a side note, you can also change the add_header arguments to match this Python docs example:

    part.add_header('Content-Disposition', 'attachment', filename='attachthisfile.csv')
    

    Full working example:

    import smtplib
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    from email.mime.text import MIMEText
    from email.utils import COMMASPACE
    from email import encoders
    
    SUBJECT = 'Subject string'
    FILENAME = 'attachthisfile.csv'
    FILEPATH = './attachthisfile.csv'
    MY_EMAIL = 'example@yahoo.com'
    MY_PASSWORD = '********************'
    TO_EMAIL = 'example@gmail.com'
    SMTP_SERVER = 'smtp.mail.yahoo.com'
    SMTP_PORT = 587
    
    msg = MIMEMultipart()
    msg['From'] = MY_EMAIL
    msg['To'] = COMMASPACE.join([TO_EMAIL])
    msg['Subject'] = SUBJECT
    
    part = MIMEBase('application', "octet-stream")
    part.set_payload(open(FILEPATH, "rb").read())
    encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment', filename=FILENAME)  # or
    # part.add_header('Content-Disposition', 'attachment; filename="attachthisfile.csv"')
    msg.attach(part)
    
    smtpObj = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
    smtpObj.ehlo()
    smtpObj.starttls()
    smtpObj.login(MY_EMAIL, MY_PASSWORD)
    smtpObj.sendmail(MY_EMAIL, TO_EMAIL, msg.as_string())
    smtpObj.quit()
    

    Edit: Added full example