jewettg
jewettg

Reputation: 1163

Python: Encoding message as base64 to solve "!" and line length issue

BACKGROUND

Regarding the following articles:

All the problems and solutions refer to PHP issue, but I have run into this problem in Python.

If I send the emails directly to recipients, all is well, no exclamation marks appear, and the message displays properly.

However, utilizing our "Sympa" (https://www.sympa.org/) system that the University uses for it "mailing list" solution, emails from this system have the exclamation marks and line breaks inserted in the message and HTML breaks causing display issues.

The problem stems from line length. Any line longer than a magical 998 character length line gets this exclamation marks and line breaks inserted.

NOW THE QUESTION

One of the solutions they mention is encoding the body of a message in base64, which apparently is immune to the line length issue. However, I can not figure out how to properly form a message in Python and have the proper headers and encoding happen so the message will display properly in an email client.

Right now, I have only succeed in sending emails with base64 encode bodies as attached files. Bleck!

I need to send HTML encoded emails (tables and some formatting). I create one very long concatenated string of all the html squished together. It is ugly but will display properly.

HELP?!

NOTE: If anyone else has had this problem and has a solution that will allow me to send emails that are not plagued by line length issue, I am all ears!

Source Code as Requested

# Add support for emailing reports
import smtplib
# from email.mime.text import MIMEText
from email.mime.message import MIMEMessage
from email.encoders import encode_base64
from email.message import Message

... ...

headerData = {"rDate": datetime.datetime.now().strftime('%Y-%m-%d')}
msg_body = msg_header.format(**headerData) + contact_table + spacer + svc_table

theMsg = Message()
theMsg.set_payload(msg_body)
encode_base64(theMsg)
theMsg.add_header('Content-Transfer-Encoding', 'base64')
envelope = MIMEMessage(theMsg, 'html')

theSubject = "Audit for: "+aService['description']
envelope['Subject'] = theSubject

from_addr = "xxx@xxx"
envelope['From'] = from_addr

to_addrs = "xxx@xxxx"
# to_addrs = aService['contact_email']
envelope['To'] = to_addrs

# Send the message via our own SMTP server.
s = smtplib.SMTP('x.x.x.x')
s.sendmail(from_addr, to_addrs, envelope.as_string())
s.quit()

SOLUTION, thank you @Serge Ballesta Going back to MIMEText, and specifying a character set seemed to do the trick:

envelope = MIMEText(msg_body, 'html', _charset='utf-8') 
assert envelope['Content-Transfer-Encoding'] == 'base64'

envelope['Subject'] = "Audit for: "+aService['description']

from_addr = "[email protected]"
envelope['From'] = from_addr

to_addrs = "[email protected]"
envelope['To'] = to_addrs

# Send the message via our own SMTP server.
s = smtplib.SMTP('xx.xx.xx.edu')
s.sendmail(from_addr, to_addrs, envelope.as_string())
s.quit()

Apparently I was just stabbing around and did not account for character set. Using MIMEText and not MIMEMessage.

Upvotes: 1

Views: 2802

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 148975

Normally, email.mime.MIMEText automatically sets the Content-Transfert-Encoding to base64 if the body is not declared to be plain ASCII. So, assuming that body contains the HTML text of the body of the message (no mail headers there), declaring it as utf-8 should be enough:

msg = email.mime.text.MIMEText(body, 'html', _charset='utf-8')

# assert the cte:
assert msg['Content-Transfer-Encoding'] == 'base64'

theSubject = "Audit for: "+aService['description']
msg['Subject'] = theSubject

from_addr = "xxx@xxx"
msg['From'] = from_addr

to_addrs = "xxx@xxxx"
# to_addrs = aService['contact_email']
msg['To'] = to_addrs

# optionally set other headers
# msg['Date']=datetime.datetime.now().isoformat()

# Send the message
s = smtplib.SMTP('x.x.x.x')
s.sendmail(from_addr, to_addrs, msg.as_bytes())
s.quit()

Upvotes: 2

Related Questions