7

I have a Python code that creates a report for a data frame from Reddit, and converts it to simple HTML and then email's it out. Below is the code:

#Clean all the Dataframes
test_clean = clean(test_test_df)
brand_clean = clean(brands_df)
competitor_clean = clean(competitors_df)
#Convert to HTML
test_html = test_clean.render()
brand_html = brand_clean.render()
competitor_html = competitor_clean.render()


# In[27]:


brand_clean


# # Email Integration

# #### Import Libraries for Email

# In[ ]:


import smtplib
from email.mime.multipart import MIMEMultipart 
from email.mime.text import MIMEText
from datetime import date


# #### Send Email If No Data is Available

# In[ ]:


if test_test_df.empty:
    today = str(date.today())

    fromaddr = "email@email.com"
    toaddr = "email@email.com"
    msg = MIMEMultipart()
    msg['From'] = fromaddr
    msg['To'] = toaddr
    msg['Subject'] = "Daily Reddit Monitor " + today


    message = "There are no relevant posts above the 100 score threshold today!"

    #email = df_complete.render()

    part1 = MIMEText(message, 'plain')


    msg.attach(part1)
    #msg.attach(part2)

    server = smtplib.SMTP('smtp.postmarkapp.com', 587)
    server.starttls()
    server.login('API-KEY”, “API-KEY')
    text = msg.as_string()
    server.sendmail(fromaddr, toaddr, text)
    server.quit()
    IpyExit 

The email that is received is very simple in format. I wanted that email to look good so wrote a HTML code with header image logo etc using HTML Tables inline CSS, in short a HTML code for news letter. Now I want that Python script to use my HTML code while sending the email so that the email when received in Inbox looks good like a news letter. Any suggestion or solution how I can achieve this?

Below is my HTML code.

<table width="689" border="0" cellspacing="0" cellpadding="1" align="center" bgcolor="#353A71">
<tr>
     <td valign="middle" align="center">

     <table width="689" border="0" cellspacing="0" cellpadding="0" bgcolor="#FFFFFF" align="center">
    <tr align="left"> 
         <td valign="top" colspan="2"> 

          <table width="100%" border="0" cellpadding="3" cellspacing="0" bgcolor="#FFFFFF">
        <tr> 
             <td width="0%">&nbsp;</td>
            <td valign="top" width="100%">

               <center><h1 style="font-family:helvetica;">Top Reddit Posts</h1></center>



                <td width="0%">&nbsp;</td>
        </tr>
        <tr>

             <td width="0%">&nbsp;</td>
               <td>&nbsp;</td>     

            <td width="0%">&nbsp;</td>
        </tr>
          <tr> 
             <td width="0%" bgcolor="#FFFFFF">&nbsp;</td>
            <td align="center" class="profileCaptionWhiteBold" width="100%" valign="top" bgcolor="#FFFFFF"> 
               </td>
               <td width="0%" bgcolor="#FFFFFF">&nbsp;</td>
        </tr>
        </table>

So I want the out put of the script to go after:

Top Reddit Posts

Piyush Patil
  • 14,512
  • 6
  • 35
  • 54
  • It looks like you already have the code for it: `MIMEText(email,'html')`? – Ricky Kim May 30 '19 at 15:47
  • Yes but the email I get is very plane in format see this sample https://imgur.com/hCoCrGu – Piyush Patil May 30 '19 at 15:50
  • 1
    Have you tried manually sending html email and see if it works? Because a lot of formatting (CSS) don't work in emails. – Ricky Kim May 30 '19 at 15:57
  • Yes that email is working and looks perfect in the inbox when I test it out. The HTML email is not a issue integrating that HTML code with this Python script is issue – Piyush Patil May 30 '19 at 15:59
  • Is the script you attached in question the actual one you're using? because it has the html part commented out. – Ricky Kim May 30 '19 at 16:02
  • Do not worry about that I removed that line – Piyush Patil May 30 '19 at 16:06
  • That was the correct code... change `MIMEText(message, 'plain')` to `MIMEText(message, 'html')` – Ricky Kim May 30 '19 at 16:07
  • Actually, I feel like the code you put on question is irrelevant/not the part you're asking: there are no html you're trying to send at all in the code. – Ricky Kim May 30 '19 at 16:15
  • The HTML code I have created is in a different file so my question is how do I integrate that HTML code into the above Python script while sending the email out. – Piyush Patil May 30 '19 at 16:33
  • @error2007s - see my answer on integrating HTML code into python for merging the HTML report from your data frame – Mike Jun 08 '19 at 23:46

3 Answers3

10

Say the HTML you have generated elsewhere is contained in the string messageHTML, then all you have to add is:

msg.attach(MIMEText(messageHTML, 'html'))

Leave the plain text in as well, so the two lines will look like

msg.attach(MIMEText(messagePlain, 'plain'))
msg.attach(MIMEText(messageHTML, 'html'))

To set up the HTML, create a variable messageHTML. Then you could create the table like so (assuming you want 1 row, with 2 columns, data_1 and data_2):

messagePlain = data_1 + " " + data_2
messageHTML = '<table><tr><td>' + data_1 + '</td><td>' + data_2 + '</td></tr></table>'

msg.attach(MIMEText(messagePlain, 'plain'))
msg.attach(MIMEText(messageHTML, 'html'))

I'd recommend starting off with a simple table, maybe not even with dynamically obtained data, to ensure that the HTML Is rendering correctly when you send it, and then it extend the HTML to the content and style you want later.

Samuel Cooper
  • 552
  • 3
  • 11
2

Your sample code wasn't very clear, but I think you are just trying to embed an existing HTML fragment (the report for a data frame from Reddit) into a larger HTML page that presents it nicely.

To do this, you can simply use a template held in a multi-line string then substitute values for placemarkers {} within it:

# Placeholder for current html report from dataframe (replace with your code)
df = pd.DataFrame([{'Title': 'Story 1 title', 'Description': 'Story 1 description'}])
redditHTML = df.to_html()

# HTML news letter template
template='''
<table width="689" border="0" cellspacing="0" cellpadding="1" align="center" bgcolor="#353A71">
    <tr>
        <td valign="middle" align="center">
            <table width="689" border="0" cellspacing="0" cellpadding="0" bgcolor="#FFFFFF" align="center">
                <tr align="left"> 
                    <td valign="top" colspan="2"> 
                        <table width="100%" border="0" cellpadding="3" cellspacing="0" bgcolor="#FFFFFF">
                            <tr> 
                                <td width="0%">&nbsp;</td>
                                <td valign="top" width="100%">
                                    <center><h1 style="font-family:helvetica;">Top Reddit Posts</h1></center>

                                    {}

                                </td>
                                <td width="0%">&nbsp;</td>
                            </tr>
                            <tr>
                                <td width="0%">&nbsp;</td>
                                <td>&nbsp;</td>     
                                <td width="0%">&nbsp;</td>
                            </tr>
                            <tr> 
                                <td width="0%" bgcolor="#FFFFFF">&nbsp;</td>
                                <td align="center" class="profileCaptionWhiteBold" width="100%" valign="top" bgcolor="#FFFFFF"></td>
                                <td width="0%" bgcolor="#FFFFFF">&nbsp;</td>
                            </tr>
                        </table>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>
'''

completeHTML = template.format(redditHTML)

msg.attach(MIMEText(completeHTML, 'html'))

Note that your HTML code example was missing a </td> to close the section containing the Top Reddit Posts, plus was missing the trailing </td> </tr> </table> to complete the news letter

Mike
  • 3,722
  • 1
  • 28
  • 41
-2

You can create an HTML-formatted email (on windows) like so:

    import win32com.client as win32   
    outlook = win32.Dispatch('outlook.application')
    mail = outlook.CreateItem(0)   
    mail.HtmlBody = html_string
    mail.To = ''
    mail.Subject = ''

etc.

delica
  • 1,647
  • 13
  • 17