Search code examples
pythonhtmlemailtextattachment

How to correctly send python email with attachment and HTML body with alternate plain text body


I am using python to send an email with an HTML body and an attachment. I also want to include a plain text email body for email clients that do not display HTML. The code sample from my application below seems to work in many cases but I have noticed that in the IOS email client that the attachment does not appear.

If I just send the email as HTML then everything seems to work but if possible I want to provide an alternate plain text body. Is there anything I am missing in my code to send both the HTML and plain text email body correctly.

Any advice much appreciated.

import smtplib
import ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

# Mail server settings
MAIL_SMTP_SERVER = "smtp.gmail.com"
MAIL_PORT = 465
MAIL_USERNAME = '***'
MAIL_PASSWORD = '***'

email_to = '*@***.com'
email_from = '#@###.com'
email_subject = 'Email test'
email_body_html = '''
        <html>
            <body>
                <h1>Email Body</h1>
                <p>Here is some text</p>
            </body>
        </html>
        '''
email_body_plaintext = 'This is the plain text body'
path='./test_doc.pdf'
name='doc.pdf'


# Create the message
mime_message = MIMEMultipart('alternative')
mime_message["From"] = email_from
mime_message["To"] = email_to
mime_message["Subject"] = email_subject

# Add  file attachment to the message
with open(path, "rb") as file_to_read:
    file_attachment = MIMEApplication(file_to_read.read())

file_attachment.add_header("Content-Disposition", f"attachment; filename= {name}")
mime_message.attach(file_attachment)

# Attach the plain text body
mime_message.attach(MIMEText(email_body_plaintext, "plain"))

# Attach the HTML body
mime_message.attach(MIMEText(email_body_html, "html"))

# Get the mime message into string format
email_string = mime_message.as_string()

# Connect to the SMTP server and Send Email
context = ssl.create_default_context()
with smtplib.SMTP_SSL(MAIL_SMTP_SERVER, MAIL_PORT, context=context) as server:
    server.login(MAIL_USERNAME, MAIL_PASSWORD)
    server.sendmail(email_from, email_to, email_string)

Solution

  • multipart/alternative can only contain a text part and an HTML part. If you want to have an additional attachment, you need a more complicated structure:

    • multipart/mixed
      • multipart/alternative
        • text/plain
        • text/html
      • application/pdf