{"id":1860,"library":"premailer","title":"Premailer","description":"Premailer is a Python library that converts HTML documents containing CSS `<style>` blocks or `<link>` tags into HTML with inline `style` attributes. It leverages `lxml` for parsing and is primarily used for preparing HTML emails, where external stylesheets are often unsupported. The library's latest stable version is 3.10.0 and it maintains an active development status.","status":"active","version":"3.10.0","language":"python","source_language":"en","source_url":"https://github.com/peterbe/premailer","tags":["html","css","email","inline-styles","lxml","email-marketing"],"install":[{"cmd":"pip install premailer","lang":"bash","label":"Install with pip"}],"dependencies":[{"reason":"Core HTML/XML parsing and manipulation.","package":"lxml","optional":false},{"reason":"CSS parsing and handling.","package":"cssutils","optional":false},{"reason":"CSS selector support for lxml.","package":"cssselect","optional":false},{"reason":"For fetching external stylesheets if 'allow_network' is True.","package":"requests","optional":false},{"reason":"Caching mechanism for performance optimizations.","package":"cachetools","optional":false}],"imports":[{"note":"A shortcut function for quick, single-document transformations. Not recommended for batch processing due to performance implications.","symbol":"transform","correct":"from premailer import transform"},{"note":"The main class for advanced usage and improved performance when processing multiple HTML documents.","symbol":"Premailer","correct":"from premailer import Premailer"}],"quickstart":{"code":"from premailer import transform\n\nhtml_content = \"\"\"\n<html>\n<head>\n<style type=\"text/css\">\nh1 { border:1px solid black }\np { color:red;}\n</style>\n</head>\n<body>\n<h1 style=\"font-weight:bolder\">Peter</h1>\n<p>Hej</p>\n</body>\n</html>\n\"\"\"\n\n# Transform the HTML to inline styles\nresult_html = transform(html_content)\nprint(result_html)","lang":"python","description":"This quickstart demonstrates the most basic usage of `premailer` using the `transform` shortcut function. It takes an HTML string with embedded CSS and converts the styles into inline attributes. For more complex scenarios or better performance when processing multiple documents, it is recommended to use the `Premailer` class directly."},"warnings":[{"fix":"If you relied on classes being removed, explicitly set `remove_classes=True` in the `Premailer` constructor or `transform` function: `transform(html, remove_classes=True)`.","message":"In version 3.0.0, the default value for the `remove_classes` option changed from `True` to `False`. This means CSS class attributes are now kept in the output HTML by default.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"For batch processing, instantiate the `Premailer` class once and reuse its `transform` method: `p = Premailer(base_url=MY_BASE_URL); for html_string in get_html_documents(): transformed = p.transform(html_string)`.","message":"Using `premailer.transform` repeatedly in a loop for multiple HTML documents can lead to poor performance, as it creates a new `Premailer` instance with each call.","severity":"gotcha","affected_versions":"All"},{"fix":"To prevent network requests, set the `allow_network=False` option: `transform(html, allow_network=False)` or `Premailer(html, allow_network=False)`.","message":"By default, `premailer` attempts to download external stylesheets specified by URLs over the network. This can introduce security risks or performance issues.","severity":"gotcha","affected_versions":"All"},{"fix":"To capture CSS parsing logs, pass a `cssutils_logging_handler` and `cssutils_logging_level` to the `Premailer` constructor. For example: `import logging; from io import StringIO; mylog = StringIO(); myhandler = logging.StreamHandler(mylog); p = Premailer(..., cssutils_logging_handler=myhandler, cssutils_logging_level=logging.INFO)`.","message":"The underlying `cssutils` library, used by `premailer` for CSS parsing, uses Python's standard `logging` module to report issues. By default, these logs might not be captured or visible.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"search_vec":"'contain':11 'convert':8 'css':12 'document':10 'html':9 'librari':6 'premail':1,2 'python':5","created_at":"2026-04-09T05:08:24.550272+00:00","updated_at":"2026-04-16T18:09:40.944111+00:00","problems":[{"fix":"Ensure your CSS is well-formed and avoid complex or unsupported `@media` rules. Consider pre-processing CSS to simplify media queries or explicitly ignore them using `data-premailer='ignore'` if premailer is not intended to handle them.","cause":"This usually happens when premailer encounters a CSS @media rule that it cannot process or that is malformed, leading to an attempt to access a 'style' attribute on a 'CSSMediaRule' object where it doesn't exist in that context.","error":"AttributeError: 'CSSMediaRule' object has no attribute 'style'"},{"fix":"Provide the HTML content either to the `Premailer` constructor (e.g., `p = Premailer(html_string, with_html_string=True)`) or as the first argument to the `transform` method (e.g., `p = Premailer(); p.transform(html_string)`), but not both.","cause":"This error occurs when the HTML content is provided both during the `Premailer` object instantiation and again as an argument to the `transform` method.","error":"TypeError: Can't pass html argument twice"},{"fix":"Disable external stylesheet loading by setting `allow_network=False` in the `Premailer` constructor, or ensure network access is available and URLs are correct. If the stylesheets are local, use `base_url` or `base_path` to help premailer locate them without network requests.","cause":"Premailer attempts to download external stylesheets referenced in the HTML (e.g., `<link rel='stylesheet' href='http://example.com/style.css'>`) but fails due to network issues, firewalls, or invalid URLs.","error":"ConnectionError: HTTPSConnectionPool(...) Max retries exceeded with url: ... Failed to establish a new connection"},{"fix":"Ensure your input HTML is well-formed. If the issue persists, try pinning `lxml` to a compatible version (e.g., `pip install lxml==4.9.4`) or update `premailer` to a version that officially supports newer `lxml` releases if available.","cause":"This error often indicates malformed HTML input that `lxml` cannot parse correctly, or an incompatibility between the `premailer` library and the installed `lxml` version, especially with `lxml > 4.9.4`.","error":"lxml.etree.XMLSyntaxError: Document is empty"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"3.10.0","cli_name":"premailer","cli_version":"sh: 1: premailer: not found","type":"library","homepage":null,"github":"http://github.com/peterbe/premailer","docs":null,"changelog":null,"pypi":"https://pypi.org/project/premailer/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["communication","serialization"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-08-28","next_check":"2026-07-28","install_tag":null}}