Search code examples
pythonemailmime

adding to an email a zip file


I have the code below that works perfectly fine when I use it to send a txt file, an image or audio. However, it doesn't work when I try to send zip files, rar files, or any other file that doesn't have its own MIME (which is not related to MIMEText, MIMEImage or MIMEAudio).

In conclusion, whenever I reach the else part (the MIMEBase command) I do something wrong and get the error:

e.send_mail(TARGET, SUBJECT, "file.zip")    
msg.attach(part)         //two lines after the else's end
AttributeError: 'str' object has no attribute 'append'

the code:

def send_mail(self, target, subject, *file_names):
    """
    send a mail with files to the target
    @param target: send the mail to the target
    @param subject: mail's subject
    @param file_names= list of files to send
    """
    msg = email.MIMEMultipart.MIMEMultipart()
    msg['From'] = self.mail
    msg['To'] = email.Utils.COMMASPACE.join(target)
    msg['Subject'] = subject
    for file_name in file_names:
        f = open(file_name, 'rb')
        ctype, encoding = mimetypes.guess_type(file_name)
        if ctype is None or encoding is not None:
            ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)
        # in case of a text file
        if maintype == 'text':
            part = MIMEText(f.read(), _subtype=subtype)
        # in case of an image file
        elif maintype == 'image':
            part = MIMEImage(f.read(), _subtype=subtype)
        # in case of an audio file
        elif maintype == 'audio':
            part = MIMEAudio(f.read(), _subtype=subtype)
        # any other file
        else:
            part = MIMEBase(maintype, subtype)
            msg.set_payload(f.read())
        part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file_name))
        msg.attach(part)
        f.close()
    # ssl server doesn't support or need tls, so don't call server_ssl.starttls()
    self.server_ssl.sendmail(self.mail, target, msg.as_string())
    #server_ssl.quit()
    self.server_ssl.close()

I have seen similar codes but I don't understand what is wrong with mine.

could you please explain me what I am messing up?

thank you!


Solution

  • if it helps anyone here is the answer: the main problem was that I changed the msg payload instead of the zip file's

    def send_mail(self, target, subject, body, *file_names):
            """
            send a mail with files to the target
            @param target: send the mail to the target
            @param subject: mail's subject
            @param file_names= list of files to send
            """
            msg = MIMEMultipart()
            msg['From'] = self.mail
            msg['To'] = target
            msg['Subject'] = subject
            body_part = MIMEText(body, 'plain')
            msg.attach(body_part)
            for file_name in file_names:
                f = open(file_name, 'rb')
                ctype, encoding = mimetypes.guess_type(file_name)
                if ctype is None or encoding is not None:
                    ctype = 'application/octet-stream'
                maintype, subtype = ctype.split('/', 1)
                # in case of a text file
                if maintype == 'text':
                    part = MIMEText(f.read(), _subtype=subtype)
                # in case of an image file
                elif maintype == 'image':
                    part = MIMEImage(f.read(), _subtype=subtype)
                # in case of an audio file
                elif maintype == 'audio':
                    part = MIMEAudio(f.read(), _subtype=subtype)
                # any other file
                else:
                    part = MIMEBase(maintype, subtype)
                    part.set_payload(f.read())
                encoders.encode_base64(part)
                part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(file_name))
                msg.attach(part)
                f.close()
            # ssl server doesn't support or need tls, so don't call server_ssl.starttls()
            self.server_ssl.sendmail(self.mail, target, msg.as_string())
            self.server_ssl.quit()