Converting Pandas DataFrame to HTML table with formatting for email

I’m trying to turn my pandas DataFrame into an HTML table for an email but I’m running into a problem. The conditional formatting I’ve set up isn’t showing up in the HTML version even though it works fine when I save it as an Excel file. Here’s what I’ve done:

import pandas as pd

df = pd.read_csv('data.csv')

def color_rows(row):
    return ['background-color: yellow'] * len(row) if row['Column1'] < 1 else [''] * len(row)

styled_df = df.style.apply(color_rows, axis=1)

# This works fine
styled_df.to_excel('output.xlsx', index=False)

# This doesn't keep the yellow highlighting
html_table = styled_df.to_html(index=False)

# Then I add some CSS and put it in an email template

Does anyone know why the HTML table isn’t keeping the yellow highlights? Is there a trick to make this work for emails? Thanks for any help!

hey laura, i’ve run into this too. email clients can be a pain with css. have you tried using inline styles instead? like this:

df['style'] = df['Column1'].apply(lambda x: 'background-color: yellow;' if x < 1 else '')
html_table = df.to_html(index=False, escape=False, formatters={'style': lambda x: f'style="{x}"'})

this adds the style directly to each cell. might work better for emails.

I’ve encountered this issue before when sending HTML tables in emails. The problem is that email clients often strip out or ignore certain CSS styles for security reasons.

Here’s a workaround that worked for me:

Instead of using Pandas’ built-in styling, you can manually add the background color to each cell in the HTML. After generating the basic HTML table, parse it with BeautifulSoup and add inline styles directly to the elements.

Something like this:

from bs4 import BeautifulSoup

html_table = df.to_html(index=False)
soup = BeautifulSoup(html_table, 'html.parser')

for row in soup.find_all('tr')[1:]:  # Skip header row
    if float(row.find_all('td')[0].text) < 1:
        for td in row.find_all('td'):
            td['style'] = 'background-color: yellow;'

formatted_html = str(soup)

This approach adds inline styles, which are more likely to be preserved in email clients. Just remember to install BeautifulSoup if you haven’t already.

Hope this helps solve your formatting issue!

I’ve dealt with this issue before when sending data tables via email. The problem stems from email clients being finicky with CSS. Here’s a solution that’s worked well for me:

Instead of using Pandas styling, you can leverage HTML attributes for coloring. Try this approach:

def color_rows(val):
    return 'bgcolor=\"yellow\"' if val < 1 else ''

html_table = df.to_html(index=False, escape=False, 
                        formatters={'Column1': lambda x: f'<td {color_rows(x)}>{x}</td>'})

This method embeds the color directly into the HTML structure using the ‘bgcolor’ attribute, which is more widely supported by email clients. It’s a bit old-school, but it gets the job done reliably across different platforms.

Remember to test your email with various clients to ensure consistent rendering.