1

I am trying to send an excel file via email but somehow the format and text is altered. I am using python3 and MIMEMultipart().

message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message.attach(MIMEText(body, "plain"))

filename = "file_name.xlsx"  # In same directory as script
# Open PDF file in binary mode
with open(filename, 'r') as attachment:
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

encoders.encode_base64(part)
message.attach(part)
text = message.as_string()

# Log in to server using secure context and send email
context = ssl.create_default_context()
with smtplib.SMTP_SSL(smtp_server, 465 , context=context) as server:
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, text)
tripleee
  • 175,061
  • 34
  • 275
  • 318

1 Answers1

3

The comment is wrong; you are not opening the file in binary mode ('rb') and so you are basically corrupting it

Following up on my answer to your previous question, here is a refactored version of your code to use the modern, Python 3.6+ EmailMessage library instead.

from email.message import EmailMessage

... 
message = EmailMessage()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message.set_content(body, 'plain')

# The OS will look in the current working directory, not in the directory where you saved the script
filename = "file_name.xlsx"
# Notice 'rb'
with open(filename, 'rb') as attachment:
    message.add_attachment(
        attachment.read(),
        maintype='application', subtype='octet-stream')

# AGAIN, no need for a context if you are just using the default SSL
with smtplib.SMTP_SSL(smtp_server, 465) as server:
    server.login(sender_email, password)
    # AGAIN, prefer the modern send_message method
    server.send_message(message)

As you notice, there's quite a lot less boilerplate than with the older Email.Message API from Python 3.5 or earlier.

A common arrangement is to have a multipart/related message with body text and an attachment, but the body text represented as a multipart/alternative structure with both a text/plain and a text/html rendering of the message. If you want this, the "asparagus" example from the email module documentation's examples page contains a recipe which demonstrates that (though it also includes an image instead of a binary attachment, and displays it inline in the HTML attachment).

Tangentially, you might be better off choosing a less clunky format than Excel for sharing data. If it's just a table, a CSV text file would be a lot smaller as well as easier to process on the receiving end. (If you do send Excel, probably actually use its designated MIME type rather than the generic application/octet-stream.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • After running the code i am getting another error. Traceback (most recent call last): File "file_path_for_script", line 39, in server.send_message(message) File "....Python\Python39\lib\smtplib.py", line 986, in send_message return self.sendmail(from_addr, to_addrs, flatmsg, mail_options, File "...\AppData\Local\Programs\Python\Python39\lib\smtplib.py", line 901, in sendmail raise SMTPRecipientsRefused(senderrs) smtplib.SMTPRecipientsRefused: {} – OneTouchForHeight Jan 27 '22 at 14:59
  • That means the SMTP server refused to send the message, probably because you failed to authenticate or because you don't have permission to send to some or all of those recipients. – tripleee Jan 27 '22 at 17:42
  • `with smtplib.SMTP(smtp_server, port=587) as server: server.ehlo() server.starttls() server.login(EMAIL_ADDRESS, EMAIL_PASSWORD) server.send_message(msg) ` I used SMTP instead of SMTL_SSL and addition two more lines and it worked but attachment text is corrupted. – OneTouchForHeight Jan 28 '22 at 14:58
  • The lack of SSL support in your SMTP server seems irrelevant for the actual question here; perhaps ask a different question if you need help understanding that (but the short answer is you simply have to know which features the server supports; ask the admin). – tripleee Jan 28 '22 at 15:03
  • How exactly is the attachment corrupted? Can you edit your question to show a small binary (probably not an Excel file necessarily) and how the resulting message is corrupted, by including the output of `print(message.as_string())`? (Or perhaps ask this as a new question if you want to avoid having to change the question drastically.) – tripleee Jan 28 '22 at 15:07