send email with a pandas dataframe as attachment

后端 未结 1 883
礼貌的吻别
礼貌的吻别 2021-01-02 23:01

I have a pandas dataframe that I am looking to convert into an xlsx and attach to an email. I can send emails based on outlook(this is the only way I can do it). I am able t

相关标签:
1条回答
  • 2021-01-02 23:26

    Have you tried to play with the io module in Python 3? It allows you to use streams as file-like objects, so that APIs that expect a file can read from or save their content to the stream instead.

    That works nicely, using a StringIO along with pandas.DataFrame.to_csv:

    import io
    
    def export_csv(df):
      with io.StringIO() as buffer:
        df.to_csv(buffer)
        return buffer.getvalue()
    

    That works, because to_csv expects a string (interpreted as a path) or a file handle, and StringIO can be used like a file handle. Unfortunately, pandas.DataFrame.to_excel works with either a string (interpreted as a path) or an ExcelWriter. In that case, we need to create the ExcelWriter ourselves, and wrap a BytesIO with it.

    import io
    import pandas as pd
    
    def export_excel(df):
      with io.BytesIO() as buffer:
        writer = pd.ExcelWriter(buffer)
        df.to_excel(writer)
        writer.save()
        return buffer.getvalue()
    

    I am not familiar with the Outlook Python tools for sending emails, I use SMTP:

    from email.mime.application import MIMEApplication
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import smtplib
    
    SEND_FROM = 'noreply@example.com'
    EXPORTERS = {'dataframe.csv': export_csv, 'dataframe.xlsx': export_excel}
    
    def send_dataframe(send_to, subject, body, df):
      multipart = MIMEMultipart()
      multipart['From'] = SEND_FROM
      multipart['To'] = send_to
      multipart['Subject'] = subject
      for filename in EXPORTERS:    
        attachment = MIMEApplication(EXPORTERS[filename](df))
        attachment['Content-Disposition'] = 'attachment; filename="{}"'.format(filename)
        multipart.attach(attachment)
      multipart.attach(MIMEText(body, 'html'))
      s = smtplib.SMTP('localhost')
      s.sendmail(SEND_FROM, send_to, multipart.as_string())
      s.quit()
    

    I hope this helps, good luck!

    0 讨论(0)
提交回复
热议问题