Does Python Have a Module to Convert CSS Styles to Inline Styles for Emails

Does Python have a module to convert CSS styles to inline styles for emails?

I had to do the same thing a while back and put the module I made for it up on GitHub https://github.com/rennat/pynliner

Format inline CSS with Python

Try the following approach:

from bs4 import BeautifulSoup
from cssutils import parseStyle

with open('input.html') as f_html:
soup = BeautifulSoup(f_html, 'html.parser')

for textarea in soup.find_all('textarea', style=True):
style = parseStyle(textarea['style'])
style['width'] = '200px'
textarea['style'] = style.cssText.replace('\n', ' ')

with open('output.html', 'w', encoding='utf-8') as f_html:
f_html.write(str(soup))

So if your HTML is:

<html>
<body>
<textarea id="123" attributeX="4" attributeY="5" style="width:159px; height:50px;"></textarea>
<textarea id="456" attributeX="4" attributeY="5" style="width:135px; height:50px;"></textarea>
<textarea id="789" attributeX="4" attributeY="5" style="width:177px; height:50px;"></textarea>
<textarea id="789" attributeX="4" attributeY="5"></textarea>
</body>
</html>

The output would become:

<html>
<body>
<textarea attributex="4" attributey="5" id="123" style="width: 200px; height: 50px"></textarea>
<textarea attributex="4" attributey="5" id="456" style="width: 200px; height: 50px"></textarea>
<textarea attributex="4" attributey="5" id="789" style="width: 200px; height: 50px"></textarea>
<textarea attributex="4" attributey="5" id="789"></textarea></body>
</html>

Here the final <textarea> is unchanged as there was no style. If required, this could be added as follows:

from bs4 import BeautifulSoup
from cssutils import parseStyle

with open('input.html') as f_html:
soup = BeautifulSoup(f_html, 'html.parser')

for textarea in soup.find_all('textarea'):
if 'style' in textarea.attrs:
# Update existing style
style = parseStyle(textarea['style'])
style['width'] = '200px'
textarea['style'] = style.cssText.replace('\n', ' ')
else:
# Add missing style
textarea['style'] = 'width: 200px; height: 50px'

with open('output.html', 'w', encoding='utf-8') as f_html:
f_html.write(str(soup))

pandas DataFrame to html with inline styles instead of CSS

One approach would be to combine Pandas' own styling with a Python module for turning CSS into inline styles (cf. e.g. this SO post).

For instance, using premailer:

In [1]: from premailer import transform

In [2]: import pandas as pd
...:
...: df = pd.DataFrame({1: [1, 2, 3], 2: [4, 5, 6]})
...:
...: def style_map(x):
...: return 'color: red' if x == 1 else 'color: blue'
...:
...: styled_df = df.style.applymap(style_map).render()

In [4]: print(transform(styled_df))
<html><head></head><body><table id="T_47851dee_4fbf_11e9_9c6a_f5d370129713"><thead> <tr> <th class="blank level0"></th> <th class="col_heading level0 col0">1</th> <th class="col_heading level0 col1">2</th> </tr></thead><tbody>
<tr>
<th id="T_47851dee_4fbf_11e9_9c6a_f5d370129713level0_row0" class="row_heading level0 row0">0</th>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row0_col0" class="data row0 col0" style="color:red">1</td>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row0_col1" class="data row0 col1" style="color:blue">4</td>
</tr>
<tr>
<th id="T_47851dee_4fbf_11e9_9c6a_f5d370129713level0_row1" class="row_heading level0 row1">1</th>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row1_col0" class="data row1 col0" style="color:blue">2</td>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row1_col1" class="data row1 col1" style="color:blue">5</td>
</tr>
<tr>
<th id="T_47851dee_4fbf_11e9_9c6a_f5d370129713level0_row2" class="row_heading level0 row2">2</th>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row2_col0" class="data row2 col0" style="color:blue">3</td>
<td id="T_47851dee_4fbf_11e9_9c6a_f5d370129713row2_col1" class="data row2 col1" style="color:blue">6</td>
</tr>
</tbody></table></body></html>

How to set default styles for Markdown in email

This is not something that can be done by Markdown itself. However, there are some Python libraries which will take HTML input (and some CSS) and output reformatted HTML with inline styles (as these answers point out). Therefore you would need to take the output of Markdown and pass it into one of those libraries.

As you are using a Django template filter (I'm assuming the filter rather than the Tag provided by Deux) to render the Markdown to HTML, you will need to create a second filter which wraps one of the CSS inliner libraries and pass the output of the Markdown filter to your custom filter. Your custom filter might look something like this (untested):

from django import template
from django.utils.safestring import mark_safe
from pynliner import Pynliner

register = template.Library()

@register.filter(name="html2email")
def pynliner_filter(value):
css = "h1 {color:#eee; font-family:'Helvetica Neue'}"
p = Pynliner()
return mark_safe(p.from_string(value).with_cssString(css).run())

Then, in your template, you would do:

{{ myvar|markdown|html2email }}

It may be interesting to note that I hardcoded the CSS right in the filter. Expanding this to be customizable is left as an exercise for the reader. Fore more specific information on creating and loading custom template filters, see Django's docs.


If you have styles defined in the template (in <style> tags), then those styles would presumably need to apply to the entire document (not just the part generated by Markdown). Note that the inliner tools will accept a complete HTML file (with CSS defined within it) and output a file which has those styles inlined. If that is your situation, then you will not need to use the custom template filter. Instead, after rendering the template, you will need to pass the HTML document through an inliner tool within your Django view. Perhaps something like this:

def someview(...)
# Do your pre-template stuff here ...
html = template.render()
p = Pyliner()
email_body = p.from_string(html).run()
# Send your email here (or whatever you are doing) ...

Without more info about your specific situation, the above code leaves a lot out. Only the relevant bits to this specific issue are addressed. There is a lot more to have a working view. Although, if you already have a working view, then presumably you would only need to replace the line which renders the template with the few lines shown above.

Why CSS is not working when sending HTML email?

Try using inline styles instead of an external stylesheet.
Like this:

<div style="color:green;" id="div"></div>

instead of something like this:

<style>
#div {
color:green;
}
</style>

<div id="div"></div>

(Thanks Kelvis Miho for pointing this out)

Edit: I searched for @Joe's text on Google, and I realized that most of it was copied from http://css-tricks.com/using-css-in-html-emails-the-real-story/ .

Edit: Joe edited his post to include the reference link.

Remember that most email clients don't support a lot of CSS, so you should mostly be using both images, and tables.

You could, for example, code a wonderful email design and then screenshot it. With tables, you could put the logo on the top in the center, the screenshoted beautiful "featured" pane on the left, the "discount" as the content in the center under the logo, ect.

Is it possible to add .css style to Jupyter notebook from separate file?

If you are okay with the styling applying to all notebooks you make, then you can store your css in ~/.jupyter/custom/custom.css and this will be automatically loaded and will override any default styles.

An alternative is to do something like this:

from IPython.core.display import HTML
import urllib2
HTML(urllib2.urlopen('[url to your css file here').read())

(from http://moderndata.plot.ly/custom-styling-for-ipython-notebooks-with-3-lines-of-code/)

Where you store your css file somewhere (e.g. on Github) and download it and apply it when you run the notebook.

If you want it to be completely external, use custom.css, but this will apply to every notebook. If you need it to only apply to a single notebook, then you'll have to specify it within the notebook, but there are less verbose ways of doing it (like above).

See configuration docs



Related Topics



Leave a reply



Submit