python - 如何在 Python 中发送带有内存压缩附件的电子邮件
问题描述
关于发送带有附件的电子邮件和在内存中创建 zip 有多个主题。尽管如此,我还是花了一些时间来结合来自不同主题的信息来编写可以创建内存 zip 并将其作为邮件附件发送的代码。下面的代码正在运行(Python 2),但我不确定我是否以最正确的方式进行操作,因为我不完全理解 io.BytesIO 的工作原理。例如,在 zipped_buffer.read() 之前我真的需要 zipped_buffer.seek(0) 吗?因此,欢迎提出任何改进建议。
我在我为发送电子邮件创建的整个类下面发布,所以我不需要重写部分代码创建内存 zip 以独立运行。而且,也许有人会发现它很有用。压缩文件由函数 __zip_in_memory 完成,附件由函数 __convert_to_attachment 创建
全班代码:
import sys,os,smtplib,email,io,zipfile
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import Encoders
class sendmail(object):
#All email data can be set at initialization
def __init__(self,mail_from="",mail_to="",subject="",body="",attachments=[],attachments2zip=[]):
self.subject=subject
self.body=body
self.mail_from=mail_from
self.mail_to=mail_to
self.attachments=attachments
self.attachments2zip=attachments2zip
self.body_lines=[]
def add_body_line(self,line):#If body lines added one by one
self.body_lines.append(line)
def set_body(self,text):#If all body text set at once
self.body=text
#Option to reuse the same instance for multiple mails
#Is it better then creating class instance for each email?
def new_mail(self,frm,to,sbj):
self.subject=sbj
self.body=""
self.mail_from=frm
self.mail_to=to
self.attachments=[]
self.attachments2zip=[]
def set_subject(self,text):#Option to set subject separately
self.subject=text
def set_from(self,text):#Option to set from separately
self.mail_from=text
def set_to(self,text):#Option to set to separately
self.mail_to=text
#Add file that will be attached to the email
def add_attachment(self,file):
self.attachments.append(file)
#Add file that will be zipped in memory and attached to the email
def add_attachment_zipped(self,file):
self.attachments2zip.append(file)
#Read file data
def __read_file(self,file):
return open(file, "rb").read()
#Read file data and zip in memory
def __zip_in_memory(self,file):
filename=os.path.basename(file)
zipped_buffer = io.BytesIO()
zf=zipfile.ZipFile(zipped_buffer,"w", zipfile.ZIP_DEFLATED)
zf.write(file, filename)
zf.close()
zipped_buffer.seek(0)
return zipped_buffer.read()
#Convert data to attachment
def __convert_to_attachment(self,data,filename):
part = MIMEBase('application', "octet-stream")
part.set_payload(data)
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"'%(filename))
self.message.attach(part)
#Create email and send it
def send(self):
self.message = MIMEMultipart()
self.message["From"] = self.mail_from
self.message["To"] = self.mail_to
self.message["Subject"] = self.subject
#message["Bcc"] = receiver_email # Recommended for mass emails
self.body=self.body+"\r\n".join(self.body_lines)
self.message.attach(MIMEText(self.body, "plain",'UTF-8'))
for file in self.attachments:#For each attachment
data=self.__read_file(file)#Get file data
filename=os.path.basename(file)
self.__convert_to_attachment(data,filename)#Attach file to the message
for file in self.attachments2zip:#For each attachment that need to be zipped
data=self.__zip_in_memory(file)#Get zipped data
filename="%s.zip"%(os.path.basename(file))
self.__convert_to_attachment(data,filename)#Attach file to the message
text = self.message.as_string()
#Send the email
server = smtplib.SMTP('localhost')
server.sendmail(self.mail_from, self.mail_to, text)
server.quit()
#Send test email
if __name__=="__main__":
import getpass
username=getpass.getuser()
m=sendmail()
m.new_mail(username,username,"Test mail")
m.add_attachment(__file__)
m.add_attachment_zipped(__file__)
m.add_body_line("Hi Alex,")
m.add_body_line("*** This is an automated message - please do not reply ***.")
m.add_body_line("Best regards.")
m.send()
解决方案
推荐阅读
- arrays - 数组值显示 coreData 值的所有信息,而不仅仅是值
- left-join - ClickHouse左连接之间
- apache-nifi - NiFi:将属性从流文件传递到另一个流中的多个文件
- linux - Apache 默认根不会更改我在 linux 服务器中的域
- laravel - 在faker中计算关系芯片中的项目
- javascript - 倒计时到html的多个实例
- .net - Azure 应用服务的响应非常慢
- chart.js - Chart JS - 动态加载时未呈现气泡图
- excel - 使用现有的 Excel 工作簿填充来自 UWP 的数据
- javascript - bootstrap-vue 的网格系统在使用 b-list-group-item 导航后中断