首页 > 解决方案 > 发送带有数据框的电子邮件作为附件

问题描述

我正在尝试创建一个函数,该函数可以发送带有作为csv文件附加的数据框的电子邮件。附加文件通常需要先将文件保存到磁盘,所以我不知道是否有任何直接的方法可以解决这个问题?

我创建了一个可以将数据帧附加为 HTML 的函数,以及一个可以将附件作为电子邮件发送的函数,但没有可以直接将数据帧作为附件发送的函数

一般设置

from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import os
_server = 'MY_SERVER'
_port = 9999
_sender = 'my.email@domain.com'

def create_simple_mail(to, title):
    mail = MIMEMultipart()
    mail['Subject'] = title
    mail['To'] = to
    mail['From'] = _sender

以 html 格式发送数据帧

def mail_dataframe_as_html(to, msg, title, df):
    mail = create_simple_mail(to, msg, title)
    html_str = msg
    html_str += '<tr></tr><tr></tr>'
    html_str += df.to_html()
    mail.attach(MIMEText(html_str, 'html'))
    smtp_connection = smtplib.SMTP(_server, _port, timeout=120)
    smtp_connection.sendmail(_sender, to, mail.as_string())

发送附件

def attach_file_to_mail(mail,f):
    with open(f, "rb") as fil:
        part = MIMEApplication(fil.read(), Name=os.path.basename(f))
        part['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(f)
        mail.attach(part)
    return mail

def mail_html(to, title, html, attachments=None):
    mail = create_simple_mail(to=to, msg=None, title=title)
    mail.attach(MIMEText(html, 'html'))
    if attachments is not None:
        for f in attachments:
            mail = attach_file_to_mail(mail,f)
    smtp_connection = smtplib.SMTP(_server, _port, timeout=120)
    smtp_connection.sendmail(_sender, to, mail.as_string())

标签: pythonpandasemailsmtpmime

解决方案


尝试使用pandas.DataFrame.to_csv
示例。
使用 pandas 数据框作为 .csv 附件发送邮件:

from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
import os
import pandas as pd
from datetime import datetime

_server = 'smtp.example.com'
_port = 587
_sender = 'some_sender@example.com'
_pass = 'pass_value'

def create_simple_mail(to, title):
    mail = MIMEMultipart()
    mail['Subject'] = title
    mail['To'] = to
    mail['From'] = _sender
    return mail

def attach_file_to_mail(mail,f):
    with open(f, "rb") as fil:
        part = MIMEApplication(fil.read(), Name=os.path.basename(f))
        part['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(f)
        mail.attach(part)
    return mail

def mail_html(to, title, html, attachments=None):
    mail = create_simple_mail(to=to, title=title)
    mail.attach(MIMEText(html, 'html'))
    if attachments is not None:
        for f in attachments:
            mail = attach_file_to_mail(mail,f)
    
    smtp_connection = smtplib.SMTP(_server, _port, timeout=120)
    

    # I tested with TLS server connection
    smtp_connection.ehlo()
    smtp_connection.starttls()
    smtp_connection.ehlo()
    smtp_connection.login(_sender, _pass)

    smtp_connection.sendmail(_sender, to, mail.as_string())


if __name__ == "__main__":

    df_data = {'num': [1, 2, 3],
        'name': ['some val 1','some val 2','some val 3'],
        'year': [2001, 2002, 2003],
        
        }

    df = pd.DataFrame(df_data, columns = ['num', 'name','year'])

    now = datetime.now() 
    date_time = now.strftime("%d_%m_%Y__%H_%M_%S")
    file_name = f'{date_time}.csv'
    df.to_csv(file_name, index = False)

    mail_html('some@example.com','Some title','<b>html text</b>',[file_name])

    # If need
    os.remove(file_name)

结果: 在此处输入图像描述


推荐阅读