bdrem & CSS in HTML mails

I'm using bdrem to get notified about current and upcoming birthdays by e-mail. ​

bdrem sends e-mails with both a text/plain and a text/html MIME part. The HTML e-mails looked nice in Thunderbird and Claws, but not so on the stock Android mail client. ​

Reason for this was that I - as it is being done on web pages - simply prepended a <style> tag to the HTML table markup. This is not supported by some mail clients, and thus background colors and watchclock-icons were missing. ​

CSS in HTML​

In HTML e-mail, you are supposed to inline all your styles: ​

<p style="color: red; padding: 5px;">..</p>

Normal <style> blocks are stripped when the e-mail is displayed to the user. ​

I think the technical reason for this behavior is that the layout of web mail clients would break when they show emails that re-define the client's layout with their <style> tags. ​

We cannot use scoped CSS in HTML yet (CSS that only gets applied to the content of a certain tag) - and probably never will. If browsers supported it, web mailers could support <style> tags without fear. ​

Inlining CSS​

I did not want to maintain two HTML variants in bdrem, so I looked for a way to re-use the existing HTML and CSS by inlining the CSS into HTML tags automatically. ​

For PHP you could use the emogrifier library, but that was a dependency I did not want to introduce. ​

Instead I opted to write the CSS inliner myself. It isn't that hard: ​

  1. Parse CSS rules into an array with the rule as key and the desired style as value ​
  2. Convert each CSS rule into XPath ​
  3. Load the HTML code with SimpleXML ​
  4. Iterate through all elements matched by the XPaths and add the style attribute ​

The CSS rules I use for bdrem are not complex, and selecting elements by class in XPath is doable. ​

In the end the method has 70 lines of code and does the job nice. ​

Size​

Inlining CSS rules into tags greatly increases the size of the HTML code, since rules are repeated again and again for every matching tag. ​

Here are the email sizes for a birthday reminder e-mail containing a list of 6 anniversaries: ​

bdrem e-mail sizes
Format Size in bytes
Plain text 846
HTML, CSS in <style> tag 4171
HTML, CSS inlined 8931

While the basic HTML version adds 300% to the plain text e-mail, just inlining CSS doubles the size of the HTML e-mail. ​

Result​

My android phone - and probably also web mailers - displays the birthday reminder mails in a nice way now: ​

Birthday reminder mail in android's mail client ​

Written by Christian Weiske.

Comments? Please send an e-mail.