Reputation: 33
I'm very new to coding in general (at least trying to get good at it anyways) and this is my first StackOverflow question despite lurking here for years and years. My apologies if it's not worded very well.
I've previously written a script that will automatically email people in both text and html with MIMEMultipart for a similar device, but in that one I had a CSV I was pulling the data from. With this new script I get serial data and perform a ser.readline on it. The information is collected from a device over a usb to RS232 cable (I have a raspberry pi that is emulating being the printer basically, receiving the data, and sending the data by email instead).
In the previous script when I was just emailing data from a csv I could use {table} within the string to bring the table into the body of the email and it all worked just fine. However with the new serial script, the newlines aren't being passed through in the same way when I use {ReportData} to insert the serial data into the email body as a string again.
Here's a sanitized version of the code:
import serial
import datetime
import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# logging settings
logging.basicConfig(filename='SerialError.log', level=logging.INFO)
f = open("Serial.log", "a+")
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
f.write(datetime.datetime.now().strftime(
"%Y-%m-%d %H:%M:%S") + " Program Starting.....\r\n")
print("Program Starting.....")
time.sleep(3)
# define variables to open serial connection and report the data
ser = serial.Serial(port='COM7', baudrate=9600, timeout=None)
ReportData = ""
# write to serial log before beginning loop
f.write(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") +
" Flushing Serial Buffer.......\r\n")
print("Flushing Serial Buffer.......")
ser.reset_input_buffer()
f.write(datetime.datetime.now().strftime(
"%Y-%m-%d %H:%M:%S") + " Waiting for serial data!\r\n")
print("Waiting for serial data!")
f.close()
# loop to read and process data as received via rs232
while True:
try:
ReceiveData = ser.readline().decode('UTF-8', 'ignore')
ReportData += ReceiveData
# find certain string and consider that the last line
if ReceiveData.find("string parse for last line i want to read") != -1:
print(ReportData.encode('UTF-8', 'ignore'))
# Text email formatting
text = """Report Data:
{ReportData}
"""
# HTML email formatting
html = """<html><body><p>Report Data:</p>
{ReportData}
</body></html>"""
# email results to recipients
smtpserver = smtplib.SMTP('mail.ourserver.com', 25)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
message = MIMEMultipart('alternative', None, [
MIMEText(text), MIMEText(html, 'html')])
message['Subject'] = 'Report Data'
message['From'] = "ReportData<[email protected]>"
message['To'] = "[email protected]"
smtpserver.sendmail(
message['From'], message['To'].split(","), message.as_string())
smtpserver.close()
# print errors upon exception
except Exception as error:
logging.exception(str(error))
print("Error: " + str(error))
exit()
If I do:
print(ReportData.encode('UTF-8', 'ignore'))
I get:
A 1
B 2
C 3
D 4
Which is what I want, but if I run my code above the email I get looks like this:
A 1 B 2 C 3 D 4
Which shows me the newline's aren't being brought into it. If I just do print
I have tried other methods of writing out the formatting, such as:
# Text email formatting
text = "Report Data:\n", ReportData.encode('UTF-8','ignore'), "\n"
# HTML email formatting
html = "<html><body><p>Report Data:</p>\n", ReportData.encode('UTF-8','ignore'), "\n</body></html>"
But this results in:
Error: 'tuple' object has no attribute 'encode'
The reason I added the .encode to try and fix it was I guessed the encoding wasn't passing through, and that was resulting in the newlines being stripped.
I also tried reading the variable into the string by using f-string:
# Text email formatting
text = f"Report Data:\n", ReportData.encode('UTF-8','ignore'), "\n"
# HTML email formatting
html = f"<html><body><p>Report Data:</p>\n", ReportData.encode('UTF-8','ignore'), "\n</body></html>"
but it gave me the same error. Then I tried the original way I wrote it in but with an f-string:
# Text email formatting
text = f"""Report Data:
{ReportData}
"""
# HTML email formatting
html = f"""<html><body><p>Report Data:</p>
{ReportData}
</body></html>"""
And it gives me the original result, just "A 1 B 2 C 3 D 4", etc... Not what I'm looking for.
I can only guess there's some easy answer I'm overlooking after reading a good amount for a couple days, but I can't seem to find it yet.
Does converting the input from ser.readline to a variable make it so using it as a variable within a string keep the newlines from being passed through? If so, what would be the best approach to get around this?
Upvotes: 3
Views: 1118
Reputation: 4572
Putting some of the answers in comment here because code reading is easier.
As martineau suggested <br>
tags are needed where newlines existed in the original text. (It's important to note that in HTML you can't just use the original text)
I would build a separate report_data
just for the html output .
def create_email_html(report_data):
report_data_html = '<br>\n'.join(report_data.split('\n'))
return f"""
<html>
<body>
<p>Report Data:</p>
{report_data_html}
</body>
</html>"""
html = create_email_html(ReportData)
will produce
<html>
<body>
<p>Report Data:</p>
A 1<br>
B 2<br>
C 3<br>
D 4<br>
</body>
</html>
Which rendered in a browser (or in this case email) will look how you are expecting it to.
Upvotes: 3