Grow your CSS skills. Land your dream job.

Dealing with Content Images in Email

Published by Chris Coyier

Let's say you're using an RSS-to-Email service. They're pretty useful. Plenty of people like subscribing to content via email. You have a CMS that generates RSS from the content you create. An RSS-to-Email service can watch for new entries, format those new entries into an email, and send them out to a list of subscribers. MailChimp and Campaign Monitor both offer this service and I'm sure they aren't the only ones.

But how do you handle images within those email-generating entries? It can be a little tricky actually, because the HTML for images that works on the website might not be so great in email.

Here's an example. You write a blog post, and the content of that blog post spits out like this:

<p>Blah blah blah. Blog post about ponies. Here's a cool and hip pony:</p>

<img src="http://cdn.ponies.what/pony.jpg" width="1200" height="800">

<p>Isn't that the best pony of all?</p>

Notice the width and height attributes. That's not entirely uncommon. WordPress automatically adds them by default if you use the Media Uploader thingy.

Even if you remove them, that pony.jpg file is still 1200x800px big, and will render that way. That's no big deal, layout-wise, on the web, because we have CSS there. We can do the classic

article img {
  max-width: 100%;
  height: auto;
}

to ensure the image doesn't break the bounds of the container it is in, or stretch it wider than appropriate. The fact that the image is that size is reasonable. That would be a @2x version of a content image in a 600px wide column, which is what is needed sometimes to make a raster image look nice and sharp.

We might even employ a responsive images technique, utilizing both JavaScript and CSS. Also a smart and reasonable thing you might want to do.

But we don't have either CSS or JavaScript available to us in emails. So that 1200x800px image is going to render at 1200x800px in an email layout. That's bad. Even on desktop, that's obnoxiously wide and hurts the ability to comfortably read the email as it can cause horizontal scrolling.

I used to use FeedBurner to provide email subscriptions on this site, and this is the kind of thing people would get.


Horizontally scrolling emails. My favorite.

It's not a problem isolated to FeedBurner. I switched to MailChimp for this service more recently. It's not their "fault", but huge images break their email layouts as well. Here's a classic example where you click "Display images below" in Gmail to reveal images and by doing so you kinda break the layout:

So we're going to need to fix this at the HTML level.

Altering the HTML

We're going to need to:

  1. If the <img> has width/height attributes, remove them
  2. Add a new width attribute with a friendly value

So these:

<img src="image.jpg" width="1200" height="800">

<img src="image.png" alt="image">

Become:

<img src="image.jpg" width="320">

<img src="image.png" width="320" alt="image">

Simple enough of a plan, but how do you actually do it?

One way is to put Email-friendly with attributes on the <img> in the content to begin with, and allow the image to be bigger with CSS on your site if needed.

Another way is to create a special feed that parses the content and alters the attributes on the <img>s as needed. I'm a fan of this way, because then it gives you a place to make other special alterations intended for email-only.

Solving in WordPress

Russell Heimlich helped me with this in this forum thread. Thanks Russell!

You'll need a create a new RSS feed in WordPress just for this. Fortunately WordPress makes this easy with add_feed(). For your functions.php file, or a custom plugin:

function css_tricks_custom_feeds() {
  add_feed('email', 'get_me_the_email_feed_template');
}
add_action('init', 'css_tricks_custom_feeds');

The email string creates a new feed with the slug email, so there is now a new feed URL at:

http://css-tricks.com/feed/email/

The get_me_the_email_feed_template string references a callback function:

function get_me_the_email_feed_template() {
  add_filter('the_content_feed', 'css_tricks_super_awesome_feed_image_magic');
  include(ABSPATH . '/wp-includes/feed-rss2.php' );
}

Which references a filter function. This filter function does the magic of altering the HTML in a post.

function css_tricks_super_awesome_feed_image_magic($content) {
  // Weirdness we need to add to strip the doctype with later.
  $content = '<div>' . $content . '</div>';
  $doc = new DOMDocument();
  $doc->LoadHTML($content);
  $images = $doc->getElementsByTagName('img');
  foreach ($images as $image) {
    $image->removeAttribute('height');
    $image->setAttribute('width', '320');
  }
  // Strip weird DOCTYPE that DOMDocument() adds in
  $content = substr($doc->saveXML($doc->getElementsByTagName('div')->item(0)), 5, -6);
  return $content;
}

This really did feel magical to me. I had no idea PHP had the native ability to query a chunk of HTML like it was the DOM and adjust attributes and stuff, like JavaScript can. But it does. Shows what I know.

Note that if the image you are inserting into the RSS entry is via something like the_post_thumbnail (the "featured image") feature in WordPress, you're already doing something special to get that into the feed, so you'd use the_post_thumbnail('medium'); instead of the_post_thumbnail('large'); or whatever.

Use the new feed

Now that this new feed exists, you can point the RSS-to-email service at it. For CSS-Tricks, I'm using MailChimp and it slurps in that feed:

MailChimp also does it's best, via media queries in the email, to make the template small screen friendly:

And it works!

I should say, it works in mobile email clients that support media queries. Which does not support GMail apps on iOS or Android, which is unfortunate.

Mobile first?

Given how often email is read on small screen devices, it's tempting to make the email template a good width for small screens, and only stretch it for large screens. If you go with a wide fixed width, even if you adjust with a media query, non supporting browsers will have a bad time:

I spoke a bit with Fabio Carneiro, the master of emails for MailChimp, who has some ideas about mobile-first emails that will work with apps that don't support media queries.

I'll update this when we can get that going. I'd also like to try setting width="100%" on images so that they just fit the container rather than the width="320" thing I'm doing now. I was just kinda afraid the 100% would still stretch the container where 320 for sure won't. Needs more testing.

I've had some luck with a <table> based design where there is no fixed width, but only max and min...

<!-- main content-wrapping table -->
<table style="min-width: 320px; max-width: 600px;">

</table>

But I can't 100% vouch for that yet.

Comments

  1. Martin_Muzatko
    Permalink to comment#

    Yay Ponies

  2. Neat trick. Thanks Chris.

  3. This really did feel magical to me. I had no idea PHP had the native ability to query a chunk of HTML like it was the DOM and adjust attributes and stuff, like JavaScript can. But it does.

    If you think the DOMDocument PHP class is neat check out the Simple HTML DOM PHP library which lets you manipulate HTML just like jQuery http://simplehtmldom.sourceforge.net/

    For this instance I didn’t need it, but for more complex things like scraping sites I rely on Simple HTML DOM heavily.

    • Permalink to comment#

      I just realize more and more that one can not simply know everything. How much expert a person can be in a field, he can’t possibly know every cool thing there is in another. World is full of such stuff. Keep calm, discover cool stuff.

  4. So I have to deal with this from time to time at work; generally the answer for this is a bit tedious.
    Currently, the method is this: hiding the images for media queries (email on a smart phone), adding the image as a background image for cells, giving some padding top, and using background-size: contain.

  5. Thanks for the tips. I’m currently using Constant Contact and struggled a bit to re-size pictures, but eventually figured it out. I am hearing good things about Mail Chimp and believe the cost is a little less. Going to check it out.

  6. Great solution! I just solved this a different way for a client but I might go back and merge the two solutions together.

    One thing you didn’t account for, however, is images that are already smaller than 320px. You probably want to keep them at their original size rather than scaling them up to 320px. You should be able to add a quick filter to accomplish this.

  7. Kali
    Permalink to comment#

    Now if you can figure out how to handle .svg, since emails don’t handle them either!

    • Hi Kali,
      You can get .svg to work in email :)

      I wrote about it here

      I need to update my article as a handful of older Android devices don’t like the JS hack I’ve used. The code at the end is up to date I just need to explain it in the write up but basically…

      You can use webkit targeting for devices with a pixel ratio of 2 to exclude those android devices
      @media all and (-webkit-min-device-pixel-ratio:2)

      Can also add in webkit email clients on desktop
      @media only screen and (-webkit-min-device-pixel-ratio: 1) and (min-width: 500px){

  8. In your emails you could also add in:
    style="white-space: pre-wrap;" to <code>

    That should stop the code blocks stretching out the width of the email.

    I’m no good at PHP but it looks pretty simple to add this in.

  9. Thanks for the info, Chris; I’d noticed the issue but didn’t have any solution to it. I borrowed what you gave us and wrote up a WordPress plugin to help other people out. It needs a bit more tweaking and then I’ll submit to the WP plugin directory. Anybody who wants to help would be welcome!

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".