Skip to content
Advertisement

How to send a complete email using smtplib python

I am trying to send an email using Python smtplib.

My objective is to include the below info in email

  1. Attachment file #works fine

  2. Paste the contents of a table in message body #works fine

  3. Write a few lines about the table (as text) in message body # not works. instead stores as an attachment

So, I tried the below code

message = MIMEMultipart()
message['Subject'] = 'For your review - files'
message['From'] = 'user2@org.com'
message['To'] = 'user1@org.com'
# code to paste table contents in outlook message window - works fine
body_content = output # this has the pretty table - html table
message.attach(MIMEText(body_content, "html"))
# code to paste the written text in outlook message window - not works. instead of writing the text in outlook body,it stores as an attachment
written_text = """
    Hi,
    How are you?"""
message.attach(MIMEText(written_text, "plain"))
# code to attach an csv file to a outlook email - works fine
with open(filename, "rb") as attachment:
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())
    encoders.encode_base64(part)
part.add_header(
"Content-Disposition",
f"attachment; filename= {filename}",
)
message.attach(part)
msg_body = message.as_string()
server = SMTP('internal.org.com', 2089)
server.sendmail(message['From'], message['To'], msg_body)
print("mail sent successfully")
server.quit()

The problem in my code is that it creates a text file (containing the message “Hi, How are you”) and sends as an attachment?

But I want “Hi, How are you” as a text message in the main Outlook message window.

Advertisement

Answer

The immediate problem is that many email clients assume that text body parts after the first are attachments. You can experiment with adding an explicit Content-Disposition: inline to the part(s) you want rendered as part of the main message, but is there a reason these need to be separate body parts in the first place? Combining the text fragments into a single body part would perhaps make more sense here.

More fundamentally, your email code was written for an older Python version. The email module in the standard library was overhauled in Python 3.6 to be more logical, versatile, and succinct; new code should target the (no longer very) new EmailMessage API. Probably throw away this code and start over with modern code from the Python email examples documentation.

from email.message import EmailMessage

message = EmailMessage()
message['Subject'] = 'For your review - files'
message['From'] = 'user2@org.com'
message['To'] = 'user1@org.com'

message.set_content(output, subtype="html")

written_text = """
    Hi,
    How are you?"""
message.add_attachment(
    written_text, subtype="plain",
    disposition="inline")

with open(filename, "rb") as attachment:
    message.add_attachment(
        attachment.read(),
        maintype="application", subtype="octet-stream",
        filename=filename)

with SMTP('internal.org.com', 2089) as server:
    server.send_message(message)
    print("mail sent successfully")
    server.quit()

If the final attachment is really a CSV file, specifying it as application/octet-stream is a bit misleading; the proper MIME type would be text/csv (see also What MIME type should I use for CSV?)

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement