How to create an email newsletter from an RSS feed

Last updated: May 30, 2022

In this tutorial, we'll use Events in Maizzle to fetch the contents of an RSS feed and display them in an HTML email newsletter.

You can preview the final result on CodePen.

Initial setup

Let's start by creating a new Maizzle project.

npx degit maizzle/maizzle example-rss

Install dependencies:

cd example-rss

npm install

Once it finishes installing dependencies, open the project in your favorite editor.

rss-parser

We'll be using rss-parser fetch the contents of the RSS feed, so let's install it:

npm install rss-parser

RSS Feed

We'll need an RSS feed to work with, so let's go with the best site for learning Laravel.

The Laracasts feed is available at https://laracasts.com/feed.

Let's add that feed URL inside the build object in config.js:

config.js
module.exports = {
  build: {
    feed: {
      url: 'https://laracasts.com/feed'
    }
  }
}

Fetch Items

We can use rss-parser inside the beforeCreate event to fetch feed data.

Edit config.js, require rss-parser, and use it in the beforeCreate event:

config.js
const Parser = require('rss-parser')

module.exports = {
  events: {
    async beforeCreate(config) {
      // create a new Parser instance
      const parser = new Parser({
        customFields: {
          feed: ['subtitle'],
          item: ['summary']
        }
      })

      // fetch and parse the feed
      let feed = await parser.parseURL(config.build.feed.url)

      // store the feed data in our config
      config.feed = {
        title: feed.title,
        subtitle: feed.subtitle,
        link: feed.link,
        updated_at: feed.lastBuildDate,
        posts: feed.items
      }
    }
  }
}

Date Format

We'll probably need to format the date of a feed item to something more readable than what the feed provides.

We can add a function to config.js and use it to format the item's date according to our audience's locale:

config.js
module.exports = {
  formattedDate(str) {
    const date = new Date(str)
    return date.toLocaleDateString('en-US', {day: 'numeric', month: 'short', year: 'numeric'})
  }
}

Template

We'll use a simplified version of the promotional template from the Starter, displaying posts as full width cards.

Let's update the existing header row:

src/templates/promotional.html
<tr>
  <td class="p-12 sm:py-8 sm:px-6 text-center">
    <a href="https://laracasts.com">
      <img src="laracasts-logo.png" width="157" alt="{{ page.feed.title }}">
    </a>
    <p class="m-0 mt-2 text-sm text-slate-600">{{ page.feed.subtitle }}</p>
  </td>
</tr>

Items Loop

Let's use a full width card from the promotional template to show a list of all items from the feed:

src/templates/promotional.html
<each loop="post in page.feed.posts">
  <tr>
    <td class="p-6 bg-white hover:shadow-xl rounded transition-shadow duration-300">
      <p class="m-0 mb-1 text-sm text-slate-500">
        {{ page.formattedDate(post.pubDate) }}
      </p>
      <h2 class="m-0 mb-4 text-2xl leading-6">
        <a href="{{ post.link }}" class="text-slate-800 hover:text-slate-700 [text-decoration:none]">
          {{ post.title }}
        </a>
      </h2>
      <p class="m-0 text-base">
        <a href="{{ post.link }}" class="text-slate-500 hover:text-slate-700 [text-decoration:none]">
          {{ post.summary }}
        </a>
      </p>
    </td>
  </tr>
  <if condition="!loop.last">
    <tr>
      <td class="h-24"></td>
    </tr>
  </if>
</each>

That's it, run npm run build to generate the production-ready email template.

Take a look at the final result on CodePen.

Resources


Copyright © 2022 Maizzle Edit this page on GitHub