Last Updated: August 19, 2016
·
10.92K
· killme2008

Inline CSS style to elements for HTML email in Java

It's from http://stackoverflow.com/questions/4521557/automatically-convert-style-sheets-to-inline-style, added a little code to process selector such as "a:hover".

import java.io.IOException;
import java.util.StringTokenizer;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.google.common.base.Strings;

/**
 * Css inliner for email,from
 * http://stackoverflow.com/questions/4521557/automatically-convert-style-sheets-to-inline-style
 * 
 * @author dennis<xzhuang@avos.com>
 * @date 2013-1-9
 */
public class AutomaticCssInliner {
    /**
     * Hecho por Grekz, http://grekz.wordpress.com
     */
    public static Document inlineStyles(String html) throws IOException {
        // Document doc = Jsoup.connect("http://mypage.com/inlineme.php").get();
        Document doc = Jsoup.parse(html);
        String style = "style";
        Elements els = doc.select(style);// to get all the style elements
        for (Element e : els) {
            String styleRules = e.getAllElements().get(0).data().replaceAll("\n", "").trim(), delims =
                    "{}";
            StringTokenizer st = new StringTokenizer(styleRules, delims);
            while (st.countTokens() > 1) {
                String selector = st.nextToken(), properties = st.nextToken();
                // Process selectors such as "a:hover"
                if (selector.indexOf(":") > 0) {
                    selector = selector.substring(0, selector.indexOf(":"));
                }
                if (Strings.isNullOrEmpty(selector)) {
                    continue;
                }
                Elements selectedElements = doc.select(selector);
                for (Element selElem : selectedElements) {
                    String oldProperties = selElem.attr(style);
                    selElem.attr(
                        style,
                        oldProperties.length() > 0 ? concatenateProperties(oldProperties,
                            properties) : properties);
                }
            }
            e.remove();
        }
        return doc;
    }

    private static String concatenateProperties(String oldProp, String newProp) {
        oldProp = oldProp.trim();
        if (!newProp.endsWith(";")) {
            newProp += ";";
        }
        return newProp + oldProp; // The existing (old) properties should take precedence.
    }
}

2 Responses
Add your response

Hi, sorry to comment on an old post, but when trying to inline css for emailing, I found your code and try it. unfortunatelly it fails on media queries because there is embedded {} inside the style element : ex :
<style>
.appleLinks, .appleLinksWhite { text-decoration: none !important; }

@media (max-width: 640px) { body[yahoo] .inner { width:100% !important; padding:0; }
</style>

Have you produced any new developpement or alternative ? regards

over 1 year ago ·

After hours of trying different manual java code solutions and not being satisfied with results (responsive media query handling issues mostly), I stumbled upon https://github.com/mdedetrich/java-premailer-wrapper which works great as a java solution. But you might be better off running your own "premailer" server. While there is a public api to premailer, I wanted to have my own instance running that I can hit as hard as I want:
https://github.com/TrackIF/premailer-server

Easy to run on ec2 with just a few clicks: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_Ruby_sinatra.html

git clone https://github.com/TrackIF/premailer-server.git
cd premailer-server
eb init  (choose latest ruby)
eb create premailer-server --sample
eb deploy
curl --data "html=<your html>" http://your.eb.url
over 1 year ago ·