I have a dataframe, In that if the value is starting with letter “A” i’m styling it in red color, now i need to send it as html table in mail but when i execute it its coming without that styling, below is the code i tried please help. please check the image for df style
import os
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import pandas as pd
def color_failed(values):
    if values.startswith("A"):
        color="Red"
    else:
        color="yellow"
    return 'color: %s' % color
def test_mail():
    try:
        server=smtplib.SMTP()
        d={"One":["Abhi","Shek"],"two":["Arjun","Echo"],"three":["Virat","Gandalf"],"four":["Emma","Amma"]}
        df=pd.DataFrame(d)
        df.style.applymap(color_failed)
 
        msg = MIMEMultipart()
        msg['Subject'] = "Testing"
        msg['From'] = mail_id
        msg['To']=mail_id
        html = """
                    <html>
                        <head>Test Email
                        <style>
                        </style>
                        </head>
                            <body>
                                {0}
                            </body>
                    </html>
                """.format(df.to_html())
        email_body = MIMEText(html, 'html')
        msg.attach(email_body)
        server.sendmail(mail_id, mail_id, msg.as_string())
Advertisement
Answer
EDIT:
I found you can assign styled dataframe to variable and use .to_html() on this dataframe.
def color_failed(values):
    if values.startswith("A"):
        color = "red"
    else:
        color = "yellow"
    return f'color: {color}'
df_styled = df.style.applymap(color_failed)
print(df_styled.to_html())       # display HTML
df_styled.to_html('index.html')  # save in file
OLD ANSWER:
df.to_html() always gives HTML without styles.
You may add some parameters in to_html(....) to change something. See doc for to_html().
You may use formatters to convert value into <div style="color: red">value</div>. It may need escape=False to put it as HTML in table.
def color_failed(value):
    if value.startswith("A"):
        color = "red"
    else:
        color = "yellow"
    return f'<div style="color: {color}">{value}</div>'
df.to_html(formatters=[color_failed, color_failed, color_failed, color_failed], escape=False)
Every column need own formatter so I repeated it 4 times in list.
Because email is not important in this problem so I skip it and I save data in file index.html and I use webbrowser to show it automatically in browser.
import pandas as pd
def color_failed(value):
    if value.startswith("A"):
        color = "red"
    else:
        color = "yellow"
    return f'<div style="color: {color}">{value}</div>'
data = {
    "one": ["Abhi", "Shek"],
    "two": ["Arjun", "Echo"],
    "three": ["Virat", "Gandalf"],
    "four": ["Emma", "Amma"]
}
df = pd.DataFrame(data)
print(df.to_html(formatters=[color_failed, color_failed, color_failed, color_failed], escape=False))
# --- show in web browser ---
df.to_html('index.html', formatters=[color_failed, color_failed, color_failed, color_failed], escape=False)
import webbrowser
webbrowser.open('index.html')
Result:
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>one</th>
      <th>two</th>
      <th>three</th>
      <th>four</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td><div style="color: red">Abhi</div></td>
      <td><div style="color: red">Arjun</div></td>
      <td><div style="color: yellow">Virat</div></td>
      <td><div style="color: yellow">Emma</div></td>
    </tr>
    <tr>
      <th>1</th>
      <td><div style="color: yellow">Shek</div></td>
      <td><div style="color: yellow">Echo</div></td>
      <td><div style="color: yellow">Gandalf</div></td>
      <td><div style="color: red">Amma</div></td>
    </tr>
  </tbody>
</table>
For more complex table you may have to format it on your own (using for-loops to work with every row and column separatelly).
