无法将PySpark DataFrame作为Excel邮件附件发送的问题求助
解决PySpark DataFrame作为Excel邮件附件发送失败的问题
问题核心原因
你当前的Excel附件代码无法运行,关键问题在于:
pandas.DataFrame.to_excel()传入文件名参数时,会直接将数据写入本地文件,返回值为None,而EmailMessage.add_attachment()需要的是文件的字节内容,不是空值或本地文件路径。- 对比CSV实现:
to_csv()不传入文件名时会返回CSV格式字符串,经encode('utf-8')后得到符合要求的字节流,因此能正常工作。
解决步骤
1. 用内存字节流替代本地文件
借助io.BytesIO将Excel内容暂存到内存中,避免写入本地文件,同时获取附件所需的字节数据。
2. 指定正确的MIME类型
.xlsx格式文件的MIME主类型为application,子类型为vnd.openxmlformats-officedocument.spreadsheetml.sheet,需在add_attachment中明确指定。
3. 安装依赖库
生成xlsx文件需要openpyxl支持,先执行安装:
pip install openpyxl
修正后的完整代码
from datetime import datetime, date import pandas as pd from pyspark.sql import Row from pyspark.sql import SparkSession import smtplib # 补充原代码遗漏的导入 from email.message import EmailMessage from io import BytesIO # 新增内存流处理工具 spark = SparkSession.builder.getOrCreate() email = EmailMessage() email['From'] = "dkfhskg" email['To'] = "dsjagjsg" email['Subject'] = "Report" mail = 'Report' email.set_content(mail , subtype='html') _smtp_server = "kdfhsajgfjdsg" _smtp_port = 10 smtp = smtplib.SMTP(_smtp_server, _smtp_port) df = spark.createDataFrame([ Row(Sno=1, Rank=4., RollNo='1000', Date=date(2000, 8, 1), e=datetime(2000, 8, 1, 12, 0)), Row(Sno=2, Rank=8., RollNo='1001', Date=date(2000, 6, 2), e=datetime(2000, 6, 2, 12, 0)), Row(Sno=4, Rank=5., RollNo='1002', Date=date(2000, 5, 3), e=datetime(2000, 5, 3, 12, 0)) ]) # 优化文件名格式,避免特殊字符 file = 'Report_' + datetime.now().strftime("%Y%m%d_%H%M%S") + '.xlsx' # 内存中生成Excel内容 excel_buffer = BytesIO() df.toPandas().to_excel(excel_buffer, index=False, sheet_name='FileReport', engine='openpyxl') excel_buffer.seek(0) # 重置缓冲区指针到起始位置 # 添加Excel附件 email.add_attachment( excel_buffer.read(), maintype='application', subtype='vnd.openxmlformats-officedocument.spreadsheetml.sheet', filename=file ) # 发送邮件并关闭连接 smtp.send_message(email) smtp.quit()
额外说明
- 若需生成
.xls格式文件,需安装xlwt库,将engine参数改为xlwt,MIME子类型改为vnd.ms-excel。 - 优化时间格式避免文件名出现空格、冒号等可能引发问题的特殊字符。
- 补充了原代码遗漏的
smtplib导入,否则会触发未定义错误。
内容的提问来源于stack exchange,提问作者Jim Macaulay
相关产品推荐
相关产品推荐

