0

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)
Bill
  • 23
  • 5

1 Answers1

0

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
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • Thanks - I'm not sure how to implement that structure though. Do I need to add an new variable and set it to application/pdf; then attach my attachment to that; and then attach that new variable to the original message? – Bill Mar 20 '23 at 00:16
  • You are creating the original message as `MimeMultipart('alternative')`. You need to create the outer shell as `MimeMultipart('mixed')`, then add your `MimeMultipart('alternative')` to that, then add your PDF attachment to the outershell as well. – Tim Roberts Mar 20 '23 at 01:09
  • Thanks for that. I restructured the way my message is created and all working. – Bill Mar 20 '23 at 09:59