In modern web development, the headless CMS approach has become increasingly popular for its flexibility and performance benefits. Recently, we tackled an interesting challenge: connecting a headless WordPress RSS feed to a Next.js website for automated newsletter distribution through Mailchimp.
This article walks through our journey, the challenges we faced, and the elegant solutions we implemented.
The Setup: Headless WordPress + Next.js + Mailchimp
Our architecture consisted of:
-
WordPress as a headless CMS (hosted on
cms.example.com
) -
Next.js website as the frontend (hosted on Vercel at
example.com
) - Mailchimp for newsletter distribution using RSS-to-Email campaigns
The goal was to automatically pull content from WordPress RSS feeds and distribute them via beautifully designed newsletters that maintained our brand consistency.
Challenge 1: RSS Feed URL Mismatch
The Problem
Our WordPress RSS feed generated URLs like:
https://cms.example.com/sample-article-slug/
But our Next.js website used URLs like:
https://example.com/news/sample-article-slug/
When newsletter subscribers clicked on articles, they were being redirected to the WordPress staging domain instead of our production Next.js site.
Initial Attempts
We first tried using Mailchimp's *|RSSITEM:SLUG|*
merge tag to construct custom URLs:
<a href="https://example.com/news/*|RSSITEM:SLUG|*">Read Article</a>
However, this approach failed because:
-
*|RSSITEM:SLUG|*
isn't a standard Mailchimp RSS merge tag -
*|RSSITEM:TITLE|*
produces URL-encoded titles with spaces (%20
) instead of proper slugs - Manual redirect mapping for each article wasn't scalable
The Solution: API-Based URL Redirection
We implemented a scalable solution using Next.js API routes:
1. Created an API route (src/app/api/redirect/route.ts
):
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const originalUrl = searchParams.get('url')
if (!originalUrl) {
return NextResponse.redirect(new URL('/news', request.url), 301)
}
try {
// Extract slug from WordPress URL
const urlObj = new URL(originalUrl)
const slug = urlObj.pathname.replace(/^\/+|\/+$/g, '')
if (slug) {
// Redirect to proper news URL
const redirectUrl = new URL(`/news/${slug}`, request.url)
return NextResponse.redirect(redirectUrl, 301)
}
} catch (error) {
console.error('Error parsing redirect URL:', error)
}
// Fallback to news page
return NextResponse.redirect(new URL('/news', request.url), 301)
}
2. Updated newsletter template to use the API route:
<a href="https://example.com/api/redirect?url=*|RSSITEM:URL|*">
Read Full Article
</a>
Challenge 2: Newsletter Design Consistency
The Problem
The default Mailchimp RSS templates looked nothing like our website. We needed the newsletter to feel like an extension of our brand, matching the exact visual design of our Next.js site.
The Solution: Custom HTML Template
We created a custom Mailchimp template that replicated our website's design system:
Design Elements Matched:
-
Color Palette:
#141414
backgrounds,#1c1c1c
content areas,#FFE52C
accent colors - Typography: Inter font family with exact same font weights and sizes
- Component Styling: Rounded corners (20px), card layouts, gradient overlays
- Responsive Design: Mobile-first approach matching website breakpoints
Key CSS Techniques:
.content-section {
background-color: #1c1c1c;
margin: 20px 15px;
padding: 32px 25px;
border-radius: 24px;
}
.category-tag {
background-color: #FFE52C;
color: #000000;
padding: 6px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
Complete Newsletter Template Structure:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>*|MC:SUBJECT|*</title>
<style type="text/css">
/* Email-safe CSS with !important declarations */
.email-container {
max-width: 600px;
margin: 0 auto;
background-color: #141414;
font-family: 'Inter', Arial, sans-serif;
}
.content-section img,
.rss-image-container img {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
display: block !important;
border-radius: 20px !important;
margin: 0 auto 25px auto !important;
}
</style>
</head>
<body style="margin: 0; padding: 0; background-color: #141414;">
<!-- RSS Feed Content -->
*|RSSITEMS:START|*
<div class="content-section">
<div class="categories">
<span class="category-tag">Newsletter</span>
</div>
<h2 class="article-title">
<a href="https://example.com/api/redirect?url=*|RSSITEM:URL|*">
*|RSSITEM:TITLE|*
</a>
</h2>
<div class="meta-info">
<span>*|RSSITEM:DATE|*</span>
<span>By *|RSSITEM:AUTHOR|*</span>
</div>
<div class="rss-image-container">
*|RSSITEM:IMAGE|*
</div>
<div class="article-content">
*|RSSITEM:CONTENT_TEXT|*
</div>
<div style="text-align: center;">
<a href="https://example.com/api/redirect?url=*|RSSITEM:URL|*"
class="read-more-btn">
Read Full Article
</a>
</div>
</div>
*|RSSITEMS:END|*
</body>
</html>
Challenge 3: RSS Image Extraction
The Problem
Getting images from RSS feeds to display properly in email clients proved challenging. Different RSS merge tags (*|RSSITEM:IMAGE|*
, *|RSSITEM:IMAGE_FULL|*
, *|RSSITEM:IMAGE_URL|*
) either didn't work or weren't supported.
The Solution: Simplified Approach
After testing various approaches, we found that *|RSSITEM:IMAGE|*
works most reliably when:
- Wrapped in a container div for better control
- Styled with email-safe CSS using
!important
declarations - Given fallback styling for different email clients
<div class="rss-image-container">
*|RSSITEM:IMAGE|*
</div>
.content-section img,
.rss-image-container img {
width: 100% !important;
max-width: 100% !important;
height: auto !important;
display: block !important;
border-radius: 20px !important;
margin: 0 auto 25px auto !important;
}
Challenge 4: Scalability Concerns
The Problem
Initially, we considered several approaches that weren't scalable:
- Manual redirects for each article in
next.config.js
- Hardcoded URL mappings
- Modifying WordPress site URLs (which would break the headless setup)
The Solution: Dynamic URL Processing
Our API route solution scales automatically because it:
- Extracts slugs dynamically from any WordPress URL
- Requires no manual configuration for new articles
- Preserves the headless architecture without modifying WordPress
- Provides proper 301 redirects for SEO benefits
The Final Architecture
Here's how everything works together:
WordPress RSS Feed
↓
Mailchimp RSS Campaign
↓
Newsletter Email
↓
User Clicks Link
↓
example.com/api/redirect?url=cms.example.com/article-slug/
↓
Extract Slug from WordPress URL
↓
301 Redirect to /news/article-slug
↓
Next.js Page Loads
Flow Example:
-
RSS URL:
https://cms.example.com/sample-article-title/
-
Newsletter Link:
https://example.com/api/redirect?url=https://cms.example.com/sample-article-title/
-
Final Destination:
https://example.com/news/sample-article-title/
Key Learnings
1. Email Client Limitations
Email clients have significant CSS limitations compared to web browsers. Using !important
declarations and inline styles is often necessary for consistent rendering.
Email-Safe CSS Practices:
/* Always use !important for critical styles */
.newsletter-content {
width: 100% !important;
max-width: 600px !important;
margin: 0 auto !important;
}
/* Inline styles as backup */
<div style="background-color: #141414; padding: 20px;">
2. RSS Merge Tag Inconsistencies
Mailchimp's RSS merge tags aren't always well-documented, and availability can vary between account types. Testing different variations is essential.
Common RSS Merge Tags:
-
*|RSSITEM:TITLE|*
- Article title -
*|RSSITEM:URL|*
- Article URL -
*|RSSITEM:DATE|*
- Publication date -
*|RSSITEM:AUTHOR|*
- Article author -
*|RSSITEM:CONTENT_TEXT|*
- Article content -
*|RSSITEM:IMAGE|*
- First image from content
3. Headless CMS URL Management
When using headless CMSs, URL management becomes more complex. Planning for URL structure differences early in the project saves significant refactoring later.
4. API Routes for Complex Logic
Next.js API routes are perfect for handling complex URL transformations that can't be solved with simple redirects or middleware.
Performance Benefits
Our final solution provides several performance advantages:
- Single 301 Redirect: Users experience only one redirect, minimizing load time
- Cached API Responses: Vercel caches API route responses for improved performance
- SEO-Friendly: Proper 301 redirects maintain link equity
- Scalable: No performance degradation as content volume grows
Implementation Steps
Step 1: Create the API Route
// src/app/api/redirect/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const originalUrl = searchParams.get('url')
if (!originalUrl) {
return NextResponse.redirect(new URL('/news', request.url), 301)
}
try {
const urlObj = new URL(originalUrl)
const slug = urlObj.pathname.replace(/^\/+|\/+$/g, '')
if (slug) {
const redirectUrl = new URL(`/news/${slug}`, request.url)
return NextResponse.redirect(redirectUrl, 301)
}
} catch (error) {
console.error('Error parsing redirect URL:', error)
}
return NextResponse.redirect(new URL('/news', request.url), 301)
}
Step 2: Create Custom Mailchimp Template
- Go to Mailchimp Templates
- Create new template → Code your own
- Paste the custom HTML template
- Configure RSS campaign to use this template
Step 3: Configure RSS Campaign
- Create new RSS campaign in Mailchimp
- Enter your WordPress RSS feed URL:
https://cms.example.com/category/newsletter/feed/
- Select your custom template
- Configure sending frequency and audience
Step 4: Test the Flow
- Send test newsletter
- Click article links
- Verify redirects work:
example.com/api/redirect?url=...
→example.com/news/article-slug
Troubleshooting Common Issues
Images Not Loading
- Ensure WordPress RSS feed includes proper image tags
- Test different RSS image merge tags (
*|RSSITEM:IMAGE|*
,*|RSSITEM:IMAGE_FULL|*
) - Check image URLs are absolute, not relative
Redirects Not Working
- Verify API route is deployed to production
- Check URL encoding in newsletter links
- Test API route directly in browser
Newsletter Design Issues
- Use
!important
for critical CSS - Test in multiple email clients
- Provide fallback styles for unsupported properties
Security Considerations
URL Validation
// Validate URLs to prevent open redirects
const allowedDomains = ['cms.example.com']
const urlObj = new URL(originalUrl)
if (!allowedDomains.includes(urlObj.hostname)) {
return NextResponse.redirect(new URL('/news', request.url), 301)
}
Rate Limiting
Consider implementing rate limiting on the redirect API route to prevent abuse:
// Basic rate limiting example
const rateLimitMap = new Map()
export async function GET(request: NextRequest) {
const ip = request.ip || 'unknown'
const now = Date.now()
const windowMs = 60000 // 1 minute
const maxRequests = 100
const requestLog = rateLimitMap.get(ip) || []
const recentRequests = requestLog.filter(time => now - time < windowMs)
if (recentRequests.length >= maxRequests) {
return new Response('Too Many Requests', { status: 429 })
}
recentRequests.push(now)
rateLimitMap.set(ip, recentRequests)
// Continue with redirect logic...
}
Conclusion
Building a scalable connection between headless WordPress RSS feeds and Next.js websites requires careful consideration of URL management, design consistency, and email client limitations. Our solution demonstrates that with the right architecture—using API routes for dynamic URL processing and custom HTML templates for brand consistency—you can create a seamless experience that scales automatically.
The key is to embrace the flexibility of modern web architecture while understanding the constraints of email clients and RSS feed limitations. By treating the newsletter as an extension of your website rather than a separate entity, you can maintain brand consistency and provide a superior user experience.
This approach has proven robust and scalable, handling growing content volume without requiring manual intervention for each new article. The investment in proper architecture pays dividends in reduced maintenance overhead and improved user experience.
What's Next?
Have you implemented similar solutions for headless CMS + newsletter integration? What challenges did you face? Share your experiences in the comments below!
If you found this helpful, consider following me for more JAMstack architecture insights and modern web development tutorials.
This implementation showcases the power of modern JAMstack architecture, demonstrating how headless CMSs, static site generators, and API-driven solutions can work together to create sophisticated, scalable web experiences.
Top comments (0)