Search code examples
pythonpython-3.xemailsmtpsmtplib

Email attachment file names are removed with AT00001


Sending mail with multiple attachments is removing attachment file names. The attachment name is changed to ATT00001.xlsx. As per following link, 'body' section added before attachment, but no luck.

https://exchange-server-guide.blogspot.com/2015/11/att00001.txt-file-fix-email-attachment-issue.html

For reference, sharing the following code snippet. Any suggestion is appreciated.

msg = MIMEMultipart()
ctype = content_type
maintype, subtype = ctype.split('/', 1)
msg['Subject'] = subject
msg['To'] = 'abc@sample.com'
msg['From'] = sender
smtp_client = smtplib.SMTP(smtp_host + ':' + smtp_port)
smtp_client.starttls()
smtp_client.login(sender, smtp_login_password)
body_part = MIMEText(body, 'plain')
msg.attach(body_part)
for file_path in file_paths :
    temp_arr = file_path.split('/')
    file_name = temp_arr[len(temp_arr) - 1]
    msg.add_header('Content-Disposition', 'attachment', filename=file_name)
    fp = open(file_path, 'rb')
    attachment = MIMEBase(maintype, subtype)
    attachment.set_payload(fp.read())
    fp.close()
    encode_base64(attachment)
    msg.attach(attachment)
smtp_client.sendmail(sender, 'abc@sample.com', msg.as_string())
smtp_client.quit() 

Solution

  • You are adding the Content-Disposition: to the multipart container. You should add it to each individual body part.

    Change this:

    for file_path in file_paths :
        temp_arr = file_path.split('/')
        file_name = temp_arr[len(temp_arr) - 1]
        msg.add_header('Content-Disposition', 'attachment', filename=file_name)
        fp = open(file_path, 'rb')
        attachment = MIMEBase(maintype, subtype)
        attachment.set_payload(fp.read())
        fp.close()
        encode_base64(attachment)
        msg.attach(attachment)
    

    to something like

    for file_path in file_paths:
        file_name = file_path.split('/')[-1]
        attachment = MIMEBase(maintype, subtype)
        with open(file_path, 'rb') as fp:
            attachment.set_payload(fp.read())
        attachment.add_header('Content-Disposition', 'attachment', filename=file_name)
        encode_base64(attachment)
        msg.attach(attachment)
    

    where I also took the liberty to switch to using a context manager (with statement). I also simplified the file name extraction.