0

When I send an e-mail with attachement (a excel document) using python and smtplib, the document that is in attachement lose his extention and turn into a .bin file for no reason.

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders


Smail = "example@hotmail.com"
Smailpass = "password"
Rmail = "example@yahoo.com"

msg = MIMEMultipart()
msg['From'] = Smail
msg['To'] = Rmail
msg['Subject'] = "Subject of the Mail"
MailMSG = "this is a test py"

msg.attach(MIMEText(MailMSG, 'plain'))
# attach file
myfile = "document.xlsx"
attachment = open("custom directory/document.xlsx", "rb")

p = MIMEBase('application', 'octet-stream')
p.set_payload((attachment).read())
encoders.encode_base64(p)
p.add_header('Content-Decomposition', 'attachment, filename="document.xlsx"')
msg.attach(p)
# login and send
Mailserver = smtplib.SMTP("smtp.live.com", 587)
Mailserver.ehlo()
Mailserver.starttls()
Mailserver.login(Smail, Smailpass)
text = msg.as_string()
Mailserver.sendmail(Smail, Rmail, text)
Mailserver.quit()
Darky
  • 15
  • 5
  • 1
    can you try to change the second argument of `add_header` to `'attachment; filename="document.xlsx"'`? – vadimb Jan 27 '20 at 12:34

1 Answers1

0

You have multiple typos here.

p.add_header('Content-Decomposition', 'attachment, filename="document.xlsx"')

The name of the header is Content-Disposition and you should have a semicolon after the disposition, not a comma.

p.add_header('Content-Disposition', 'attachment; filename="document.xlsx"')

There used to be a time when specifying the filename in the Content-Disposition: header was insufficient, so some clients still have a "belt and suspenders" fallback and also add ; name="document.xslx" to the Content-Type: application/octet-stream body part header. Perhaps also use the standard IANA content type for Excel; see What is a correct mime type for docx, pptx etc? which suggests application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

... so in summary, you should be looking at something like

Content-Type: multipart/mixed; boundary="===============5298122497454831280=="
MIME-Version: 1.0
From: example@hotmail.com
To: example@yahoo.com
Subject: Subject of the Mail

--===============5298122497454831280==
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

this is a test py
--===============5298122497454831280==
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;
     name="document.xlsx"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="document.xlsx"

77+/dHJpcGzuu64=

--===============5298122497454831280==--

(where I have replaced the base64 data with a simple placeholder).

(Also, Python stupidly insists on adding a MIME-Version: header to each body part, but this is completely unnecessary.)

tripleee
  • 139,311
  • 24
  • 207
  • 268
  • the program still works but the mail attachement still change to a .bin – Darky Jan 27 '20 at 13:09
  • Can you show what `text` looks like just before sending, and compare to the message you eventually receive? I'm thinking there will be some shenanigans on the server side. – tripleee Jan 27 '20 at 13:09
  • @Darky you can try to `import base64`, and then set the payload like `p.set_payload(base64.b64encode(attachment.read()))` and get rid of `encoders.encode_base64(p)`. Basically this will read the attachment in binary, then encode it in base64, and then of course set the header as you have already done. See if this works – small_cat_destroyer Jan 28 '20 at 00:21
  • @small_cat_destroyer I try but I got this error: `Traceback (most recent call last): File "automail.py", line 61, in p.set_payload(base64.b64encode(attachment).read()) File "/usr/lib/python3.7/base64.py", line 58, in b64encode encoded = binascii.b2a_base64(s, newline=False) TypeError: a bytes-like object is required, not '_io.BufferedReader'` – Darky Jan 30 '20 at 14:35
  • 1
    You transcribed the code incorrectly, you have `b64encode(attachment).read()` where @small_cat_destroyer had `b64encode(attachment.read())` – tripleee Jan 30 '20 at 14:42
  • https://ideone.com/h8n93Y creates a perfectly well-formed message. If you are using a mail client from the previous millennium (and/or from Microsoft, which probably amounts to roughly the same thing) try adding a fallback `; name="document.xlsx"` to the `Content-Type:` header of the attachment as well. – tripleee Jan 30 '20 at 14:59