如何使用smtplib发送Pandas DataFrame生成的内存中CSV附件
直接在内存中把Pandas DataFrame作为CSV邮件附件发送
当然可以跳过写入临时文件的步骤!直接在内存里完成这个需求的方法很简单,核心思路是用Python的io模块创建内存缓冲区,把DataFrame导出的CSV内容存到缓冲区里,再把这个缓冲区当作附件添加到邮件中。下面是完整的实现方案:
需要用到的库
你需要提前安装pandas,其他库(smtplib、email、io)都是Python标准库,不用额外安装。
完整代码示例
import pandas as pd import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders import io # 1. 创建示例DataFrame(替换成你的实际数据) df = pd.DataFrame({ '姓名': ['张三', '李四', '王五'], '年龄': [28, 32, 25], '部门': ['产品部', '技术部', '市场部'] }) # 2. 将DataFrame写入内存缓冲区(不用存到本地文件) # 注意:如果有中文,建议用BytesIO并指定utf-8编码避免乱码 csv_buffer = io.BytesIO() df.to_csv(csv_buffer, index=False, encoding='utf-8') # 把缓冲区指针移到开头,否则读取时会从末尾开始,得到空内容 csv_buffer.seek(0) # 3. 构建邮件内容 sender_email = "你的邮箱@example.com" receiver_email = "收件人邮箱@example.com" email_password = "你的邮箱密码/应用专用密码" # 比如Gmail需要用应用专用密码,不是登录密码 # 创建多部分邮件对象(支持正文+附件) msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = receiver_email msg['Subject'] = "内存生成的CSV附件测试邮件" # 添加邮件正文 email_body = "这是一封包含内存生成CSV附件的测试邮件,请查收。" msg.attach(MIMEText(email_body, 'plain', 'utf-8')) # 4. 将内存缓冲区的内容转换成邮件附件 # 创建附件对象 attachment = MIMEBase('application', 'octet-stream') attachment.set_payload(csv_buffer.read()) # 对附件内容进行Base64编码(邮件传输要求) encoders.encode_base64(attachment) # 设置附件的文件名和头部信息 attachment.add_header( 'Content-Disposition', 'attachment', filename='员工信息.csv' # 收件人看到的附件文件名 ) # 把附件添加到邮件里 msg.attach(attachment) # 5. 发送邮件 try: # 替换成你的邮箱服务商SMTP配置,比如: # Gmail: smtp.gmail.com, 465(SSL) # Outlook: smtp.office365.com, 587(STARTTLS) with smtplib.SMTP_SSL('smtp.example.com', 465) as server: server.login(sender_email, email_password) server.send_message(msg) print("邮件发送成功!") except Exception as e: print(f"邮件发送失败:{str(e)}")
关键注意事项
- 编码问题:如果你的DataFrame包含中文或非ASCII字符,一定要用
io.BytesIO并指定encoding='utf-8',避免附件出现乱码。 - 缓冲区指针:写完内容后必须调用
csv_buffer.seek(0),把指针移到缓冲区开头,否则读取时会得到空内容。 - 邮箱服务商配置:不同邮箱的SMTP服务器和端口不同,比如Gmail需要开启两步验证并使用应用专用密码,不能直接用登录密码;国内邮箱比如QQ邮箱需要开启POP3/SMTP服务并使用授权码。
- 替代方案:如果你用
io.StringIO,那么在设置payload时需要把字符串转换成字节:attachment.set_payload(csv_buffer.read().encode('utf-8')),否则可能会有编码问题。
内容的提问来源于stack exchange,提问作者Pankaj Singh
相关产品推荐
相关产品推荐

