pythonemailsmtplibmimemultipart

Python sending email with either plain text or html, but not both


I am experimenting with sending emails using Python. I have run into a problem where I cannot send plain text and html in the body, only one or the other. If I attach both parts, only the HTML shows up, and if I comment out the HTML part, then the plain text shows up.

I'm not sure why the email can't contain both. The code looks like this:

from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

username = 'email_address'
password = 'password'

def send_mail(text, subject, from_email, to_emails):
    assert isinstance(to_emails, list)
    msg = MIMEMultipart('alternative')
    msg['From'] = from_email
    msg['To'] = ', '.join(to_emails)
    msg['Subject'] = subject

    txt_part = MIMEText(text, 'plain')
    msg.attach(txt_part)

    html_part = MIMEText("<h1>This is working</h1>", 'html')
    msg.attach(html_part)

    msg_str = msg.as_string()

    with smtplib.SMTP(host='smtp.gmail.com', port=587) as server:
        server.ehlo()
        server.starttls()
        server.login(username, password)
        server.sendmail(from_email, to_emails, msg_str)
        server.quit()

Solution

  • I actually believe according to 7.2 The Multipart Content-Type what you coded is correct and the email client chooses whichever it believes is "best" according to its capabilities, which generally is the HTML version . Using 'mixed' causes both versions to be displayed serially (assuming the capability exists). I have observed in Microsoft Outlook that the text version becomes an attachment.

    To see both serially:

    Instead of:

    msg = MIMEMultipart('alternative')
    

    use:

    msg = MIMEMultipart('mixed')
    

    The server.ehlo() command is superfluous.