Skip to main content


Fair warning: this post will be relevant to, like, three of you. To everyone else: Hi. Sorry. I love you.

I use Jekyll to manage this website, and I use Mailchimp’s “RSS campaigns” to email new posts to folks who’ve subscribed to my newsletter. It’s a really handy setup: I supply MailChimp with a link to a RSS feed, and when I publish a new essay, it gets emailed to my subscribers. Easy-peasy.

Except! When I first launched the newsletter, a few people let me know that some of the emails had broken images. Not all of the images were broken, mind you. An image like this would render just fine:

<img src="/assets/image.jpg" alt="" />

But something like this would be broken:

<img srcset="/large.png 1600w, /image.png 800w"
    sizes="(min-width: 50em) 50vw, 100vw"
    alt="" />

An image like this would also be broken:

    <source srcset="/assets/chart.svg" type="image/svg+xml" />
    <source srcset="/assets/chart.png, /assets/chart@2x.png 2x" />
    <img src="/assets/chart@1x.png" alt="" />

You might’ve twigged it by now, which means you’re much faster than I was: after some testing, I realized that when MailChimp parsed my RSS feed, it wouldn’t correctly resolve responsive images. When MailChimp’s software saw a plain ol’ image like <img src="/assets/image.jpg" alt="" />, it’d change its path to <img src="" alt="" /> before emailing it to my subscribers, ensuring the image was correctly pointed at my server. But for any image more complex than that—say, an image with a srcset attribute, or basically any picture elements in my posts—that wouldn’t happen, and the image would be broken.

Once I figured out the issue, I took a stab at a fix. With the help of a random StackOverflow post, I modified a small part of the RSS feed’s template—specifically, this bit:

<content type="html" xml:base="{{ post.url | absolute_url | xml_escape }}">
    {{ post.content | markdownify | xml_escape }}

And I changed it to this:

<content type="html" xml:base="{{ post.url | absolute_url | xml_escape }}">
    {{ post.content | replace: '="/', '="' | replace: ', /', ',' | replace: '', site.url | markdownify | xml_escape }}

My goodness, that certainly looks like a lot. And it is! But in plain English, here’s what that gnarly-looking set of Liquid filters is doing:

  1. First, it replaces all instances of ="/ with ="
  2. Second, it replaces all instances of ', /', ', with ','.
  3. From there, find all instances of, and replace it with the value of the site.url variable.

Why three separate steps? Well, let’s say I’ve got a srcset attribute—for example, <source srcset="/image.jpg, /image@2x.jpg 2x" />. Here’s what happens when those filters run:

  1. The first replace filter will find the ="/ in srcset="/, and rewrite the tag to <source srcset=", /image@2x.jpg 2x" />.
  2. The second replace filter will find the ', /', ', in the middle of the srcset, and rewrite the tag to <source srcset=", 2x" />.
  3. Once my srcset attribute’s been loaded up with all those fake values, I’m replacing each of them with the value of site.url. And in my _config.yml file, that’s set to—surprise!—

In other words, I’m replacing the fake URLs with, well, my URL. So at the end of all that processing, my RSS feed will be left with <source srcset=", 2x" />, which gets handed off to MailChimp—which means, in turn, that the image will reach you.

I should note that a couple quick string replacements have been fine for me, but something a little more regular expression-friendly would probably be much more resilient—and sadly, that’s not an option in Liquid, the templating language that Jekyll uses. But! This is all to say that if you haven’t used MailChimp’s RSS Campaigns before, I think they’re a marvelously straightforward way to syndicate your blog to email. However, if you’re working with any responsive images, just be mindful that you might need to process them before they’re sent out to your readers.

(And hey, if you’d like to sign up for having my blog posts infrequently emailed to you, please do. Either way, thanks for reading.)

Current page