首页 > 解决方案 > 如何在 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()

标签: pythonemailemail-attachmentszipfilesmtplib

解决方案


推荐阅读