Pynliner
Pynliner is a Python library that converts CSS styles in an HTML document to inline styles, primarily designed for crafting HTML emails to ensure consistent rendering across various email clients. It leverages BeautifulSoup for HTML parsing and cssutils for CSS processing. The current stable version is 0.8.0, released in 2019, indicating an infrequent release cadence and a current state of maintenance rather than active development.
Common errors
-
cssutils.css.CSSSyntaxError: [err] ... (e.g., 'Expected semicolon or '}', got 'invalid_token')
cause The input CSS contains syntax errors, which cssutils (Pynliner's underlying CSS parser) cannot process.fixReview and validate your CSS syntax. Use a CSS linter or validator to identify and correct any malformed rules or properties before passing the HTML to Pynliner. -
AttributeError: 'NoneType' object has no attribute 'find_all' (or similar BeautifulSoup errors like 'NoneType' object has no attribute 'select')
cause This error typically occurs when Pynliner's internal BeautifulSoup parsing cannot find an expected HTML element, and subsequent operations are attempted on a 'None' object. This can happen with malformed HTML or incorrect CSS selectors used internally by Pynliner if the HTML structure is very unusual.fixEnsure your HTML is well-formed and valid. Check for unclosed tags, incorrect nesting, or other structural issues that might confuse the HTML parser. -
Pynliner output does not include expected styles (styles are missing or incorrect in the output HTML).
cause The most common causes are using external CSS files (<link>), @import rules, or very complex/modern CSS selectors that Pynliner's older version might not fully support or correctly resolve against the HTML.fixVerify that all CSS is embedded in <style> tags. Avoid @import. Simplify complex CSS selectors if possible. Remember Pynliner processes styles in order, so later rules might override earlier ones based on specificity and document order.
Warnings
- gotcha Pynliner only processes CSS found within <style> blocks and existing 'style' attributes in the HTML string. It explicitly ignores external CSS files linked via <link rel="stylesheet"> tags.
- gotcha Pynliner does not resolve CSS @import rules within <style> blocks. Any styles imported this way will not be processed or inlined.
- gotcha The library's last release was in 2019 (v0.8.0), and development appears dormant. It may not fully support modern CSS features (e.g., Flexbox, Grid, advanced pseudo-selectors) or newer HTML5 structures, potentially leading to incomplete or incorrect inlining for contemporary web designs.
- gotcha Pynliner respects CSS specificity rules. If a style is defined with `!important` in a <style> block, it will override an existing inline style or a less specific rule, which can lead to unexpected results if not carefully managed.
Install
-
pip install pynliner
Imports
- Pynliner
from pynliner import Pynliner
Quickstart
from pynliner import Pynliner
html_content = """
<html>
<head>
<style type="text/css">
h1 { color: red; }
p { font-size: 16px; margin: 0; }
.container { background-color: #f0f0f0; padding: 20px; }
</style>
</head>
<body>
<div class="container">
<h1>Hello, Pynliner!</h1>
<p>This is a paragraph with inlined styles.</p>
</div>
</body>
</html>
"""
inliner = Pynliner()
inlined_html = inliner.from_string(html_content)
# The inlined_html string now contains the HTML with CSS styles moved inline.
# print(inlined_html)