Guide: Automated Newsletter Assembly

Step-by-step guide to building an automated newsletter assembly pipeline. Pull content, draft missing sections with AI, assemble, preview, and distribute.

This guide walks through building a complete automated newsletter assembly pipeline that runs on a schedule.

Overview

The pipeline runs weekly (or on your cadence) and:

  1. Collects ready content blocks
  2. Checks upcoming events
  3. Drafts any missing standard sections with AI
  4. Creates a newsletter and assembles blocks
  5. Sends a preview for approval

Step 1: Collect available content

# Get all ready content blocks
curl -s "$BASE_URL/content_blocks?status=ready&per_page=50" \\
  -H "Authorization: Bearer $API_KEY"

# Get events for the coming week
curl -s "$BASE_URL/events?upcoming=true&days_ahead=7" \\
  -H "Authorization: Bearer $API_KEY"

Step 2: Draft missing sections

Check what block types are covered. If there's no ceo_update, draft one:

curl -s "$BASE_URL/content_blocks/ai_draft" \\
  -X POST \\
  -H "Authorization: Bearer $API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"context": "Write a brief CEO update for the weekly newsletter. Mention the team hitting Q1 targets and the upcoming company offsite."}'

If there are events without content blocks, draft those too:

curl -s "$BASE_URL/content_blocks/ai_draft" \\
  -X POST \\
  -H "Authorization: Bearer $API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"context": "Write an event announcement for Mental Health Awareness Week starting May 18. Include links to the EAP and suggest mindfulness resources."}'

Step 3: Create and assemble the newsletter

# Create the newsletter
NEWSLETTER=$(curl -s "$BASE_URL/newsletters" \\
  -X POST \\
  -H "Authorization: Bearer $API_KEY" \\
  -H "Content-Type: application/json" \\
  -d "{
    \\"title\\": \\"Weekly Update — $(date +%B\\ %d)\\",
    \\"subject_line\\": \\"Your weekly update is here\\",
    \\"template_slug\\": \\"clean\\",
    \\"scheduled_date\\": \\"$(date +%Y-%m-%d)\\"
  }")

NEWSLETTER_ID=$(echo $NEWSLETTER | jq -r '.newsletter.id')

# Add blocks in order: CEO update first, then ready blocks, then events
for BLOCK_ID in $CEO_BLOCK $READY_BLOCKS $EVENT_BLOCKS; do
  curl -s "$BASE_URL/newsletters/$NEWSLETTER_ID/blocks" \\
    -X POST \\
    -H "Authorization: Bearer $API_KEY" \\
    -H "Content-Type: application/json" \\
    -d "{\\"content_block_id\\": \\"$BLOCK_ID\\"}"
done

Step 4: Send preview

curl -s "$BASE_URL/newsletters/$NEWSLETTER_ID/send_preview" \\
  -X POST \\
  -H "Authorization: Bearer $API_KEY" \\
  -H "Content-Type: application/json" \\
  -d '{"email": "comms-lead@company.com"}'

Running on a schedule

Use cron, GitHub Actions, or any scheduler:

# .github/workflows/newsletter.yml
name: Assemble weekly newsletter
on:
  schedule:
    - cron: '0 8 * * 1'  # Every Monday at 8am
jobs:
  assemble:
    runs-on: ubuntu-latest
    steps:
      - run: ./scripts/assemble-newsletter.sh
        env:
          API_KEY: ${{ secrets.NEWSLETTER_API_KEY }}
          BASE_URL: https://your-app.com/api/v1

With MCP (simpler)

If you're using Claude with the MCP server, the entire pipeline is a single prompt:

"Check what content we have ready, look at upcoming events, draft a CEO update about Q1 results, assemble a newsletter using the Clean template, and send a preview to me."

See MCP Server docs for setup.