2

I have the following email code written in Python 3... I would like to send email as both HTML OR plain text depending on the receiving client. However, both hotmail and gmail (I'm using the latter to send with) receive zero line feed/carriage return characters making the plain text appear on one line. My question is how do I get line feed/carriage returns in a plain text email on the receive side? Thunderbird on Linux is my preferred client but I have noticed the same problem in Microsoft's webmail hotmail also.

#!/usr/bin/env python3
# encoding: utf-8
"""
python_3_email_with_attachment.py
Created by Robert Dempsey on 12/6/14; edited by Oliver Ernster.
Copyright (c) 2014 Robert Dempsey. Use at your own peril.

This script works with Python 3.x
"""

import os,sys
import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

COMMASPACE = ', '

def send_email(user, pwd, recipient, subject, bodyhtml, bodytext):
    sender = user
    gmail_password = pwd
    recipients = recipient if type(recipient) is list else [recipient]

    # Create the enclosing (outer) message
    outer = MIMEMultipart('alternative')
    outer['Subject'] = subject
    outer['To'] = COMMASPACE.join(recipients)
    outer['From'] = sender
    outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'

    # List of attachments
    attachments = []

    # Add the attachments to the message
    for file in attachments:
        try:
            with open(file, 'rb') as fp:
                msg = MIMEBase('application', "octet-stream")
                msg.set_payload(fp.read())
            encoders.encode_base64(msg)
            msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(file))
            outer.attach(msg)
        except:
            print("Unable to open one of the attachments. Error: ", sys.exc_info()[0])
            raise

    part1 = MIMEText(bodytext, 'plain', 'utf-8')
    part2 = MIMEText(bodyhtml, 'html', 'utf-8')

    outer.attach(part1)
    outer.attach(part2)

    composed = outer.as_string()

    # Send the email
    try:
        with smtplib.SMTP('smtp.gmail.com', 587) as s:
            s.ehlo()
            s.starttls()
            s.ehlo()
            s.login(sender, gmail_password)
            s.sendmail(sender, recipients, composed)
            s.close()
        print("Email sent!")
    except:
        print("Unable to send the email. Error: ", sys.exc_info()[0])
        raise

Here is the test code:

def test_example():

some_param = 'test'
another_param = '123456'
yet_another_param = '12345'

complete_html = pre_written_safe_and_working_html

email_text = "Please see :" + '\r\n' \
                + "stuff: " + '\r\n' + some_param + '\r\n' \
                + "more stuff: " + '\r\n' + another_param + '\r\n' \
                + "stuff again: " + '\r\n' + yet_another_param, + '\r\n'

recipients = ['targetemail@gmail.com']

send_email('myaddress@gmail.com', \
           'password', \
           recipients, \
           'Title', \
           email_text, \
           complete_html)

Any suggestions would be most welcome as it seems everyone on the internet uses HTML email only. This is fine but I would like to be able to fall back to pure text for those of us who don't want to use HTML.

Thanks,

Hamid
  • 4,410
  • 10
  • 43
  • 72
Rodent
  • 1,698
  • 1
  • 12
  • 13

1 Answers1

1

I can really recommend you using yagmail (Full disclaimer: I'm the developer/maintainer).

Among its main purposes is to make it really easy to send attachments, and to send HTML code.

Default text/inline images etc is in fact wrapped in HTML (so by default emails get sent as HTML).

File names get smart guessed on content and added as well.

Just stuff it all into contents, and yagmail will do the magic.

However, and this is apparently important to you, it already sets up "alternative" mimeparts as well. No one has asked for it, so it could really use your help to mention bugs on the github tracker, if you find any.

import yagmail
yag = yagmail.SMTP('myaddress@gmail.com', 'password')

contents = ['/local/file.png', 'some text',
            '<b><a href="https://github.com/kootenpv/yagmail">a link</a></b>']

yag.send(to='targetemail@gmail.com', subject='Title', contents = contents)

You can also set it up to be passwordless, then you can login without having username/password in script, i.e.

yag = yagmail.SMTP()

Hope to have helped!

Most questions can be answered by reading the readme on github: https://github.com/kootenpv/yagmail

PascalVKooten
  • 20,643
  • 17
  • 103
  • 160
  • Thanks for your serious efforts to help PascalvKooten. Unfortunately, though you solved the problem I had with carriage return/line feeds on pure text mails, yagmail has at least 3 bugs (I reported them on github as best I could) I discovered which prevent me from using it in the way I desire just yet. – Rodent Oct 05 '15 at 09:12
  • FYI, I am now using yagmail for pure text emails and it works great; thanks. I have dropped support for mime/alternate for now so this is no longer a pending issue for me at present. – Rodent Nov 06 '15 at 14:36
  • Is it actually possible to create multipart messages with plaintext separated from html? – fiscblog Dec 08 '20 at 10:49