Building an RSS feed from scratch is really simple, but for the fact that everyone and their mum has a garbage, non-entity SEO filler article about it. Sifting through that noise took me an hour of cold research and two different search engines.
Here's what you need —
I always target RSS 2.0. Here are some key facts —
- Any RSS feed file must declare a channel.
- That channel must have
<title>,<link>and<description>fields. - That channel will then encompass a number of
<item>tags, which are your individual articles. - Each
<item>should also have a<title>,<link>and<description>element as a rule of thumb. - The
<description>may contain a simple summary of the article being linked to, or may syndicate the entire page content as simple, entity-encoded HTML with no additional classes/IDs or styling.
Body
<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Harley Denham — Now</title>
<link>http://lichendust.com/microfeed</link>
<description>Monthly updates and ramblings from Harley Denham</description>
<language>en-gb</language>
<lastBuildDate>
$ rssdate
</lastBuildDate>
<atom:link href="https://lichendust.com/microfeed.xml" rel="self" type="application/rss+xml"/>
<item>...</item>
<item>...</item>
</channel>
</rss>Items
<item>
<title>My Article Title</title>
<link>https://lichendust.com/microfeed#2025-08-17</link>
<description><![CDATA[<p>some paragraph</p>]]></description>
<enclosure url="https://cdn.com/image.jpg" type="image/jpg"/>
<pubDate>Sun, 17 Aug 2025 14:06:14 +0100</pubDate>
<guid isPermaLink="false">2025-08-17-my-article-title</guid>
</item>The individual components of an <item> are all optional, but as mentioned, I like to always have a <title>, <link> and <description>. Most RSS readers will probably fail you if you don't have a link.
I know mine, Inoreader, is happy to receive items without titles, but frankly, it's quite ugly to have items that are just titled by their feed name. In more traditional, barebones RSS readers like Vore, a missing title is a blank entry, which is really gross.
The guid element may be a URL, but because I like to plan ahead for re-arranging my feed (i.e: archiving), making the GUID be a simple slug of the date and title is a good idea. In order for this to work, the isPermaLink="false" attribute must be added to the tag.
Dates
All dates, such as for <pubDate> and <lastBuildDate>, use RFC 822 formats, which look like this —
Mon, 01 July 2024 10:00:00 GMTGMT is interchangeable with UT (not UTC per the spec), but all variations of RSS specifications I've read seem to prefer demonstrating with GMT. Because it's also a bit of a pain to get a clean three-character UTC time zone in various time-formatting libraries, I've taken to just encoding the offset, which is much more reliably available.
GNU Date
date "+%a, %d %b %Y %H:%M:%S %z"In C/Lua
os.date('%a, %d %b %Y %H:%M:%S %z', unix_time)These come from C's strftime. %Z will give you GMT Summer Time instead of BST, for example. I believe you can force this by manually setting the locale before formatting, but it's not trivial to do this in Lua.
In Go
t := time.Now()
t.Format("Mon, 02 Jan 06 15:04:05 -0700")Note with Go, you can't use the built-in RFC822 constant because it's missing the Day, prefix. This is because the Go development team are hacks and the time module is a front-runner for the worst standard library package of all time. My favourite addendum I've seen them make to it recently is sheepishly admitting they were wrong to enforce an American Month-Day-Year ordering for the magic date, which is — and this is true — the only objectively wrong way to write a date.