Skip to main content
Admin Modules

Newsletter

Full newsletter platform: subscriber management, campaign composer with A/B testing, digest builder, templates, automations, analytics, and open/click tracking

March 16, 2026

Newsletter Platform

The Newsletter module at /admin/newsletter is a full-featured email newsletter platform built into the ArgoBox admin area. It handles the entire lifecycle: subscriber acquisition, list management, campaign composition with A/B testing, template library, automation workflows, email delivery via Resend, and open/click analytics with tracking pixels.

The platform is built on the three-tier modular architecture. The core logic lives in a standalone npm package (@argobox/newsletter), with ArgoBox-specific database and delivery adapters in Tier 2, and the admin UI in Tier 3.


Admin Dashboard

The admin page (/admin/newsletter) has six tabs, each covering a different aspect of the platform.

Dashboard Tab

Overview of the newsletter's health and activity:

  • Stats cards -- Total subscribers, active, confirmed, and unsubscribed counts
  • Growth chart -- 30-day subscriber acquisition trend
  • Top campaigns -- Recent campaigns ranked by engagement (opens, clicks)
  • Recent events -- Live feed of tracking events (opens, clicks, unsubscribes)

All data is fetched from /api/newsletter/analytics.

Subscribers Tab

Full subscriber list management with search, pagination, import/export:

  • Search by email or name
  • Per-subscriber details -- Email, name, source, subscription date, confirmed status, engagement score
  • CSV Import -- Upload a CSV file with at minimum an email column header. Supports optional name, source, and tags columns
  • CSV Export -- Download the full subscriber list as CSV via /api/newsletter/export
  • Inline actions -- Unsubscribe or delete individual subscribers

Composer Tab

Campaign creation with rich HTML editing and A/B testing:

  • Subject line with optional A/B variant (ab_subject_b)
  • Rich HTML body editor with preview
  • Preview text -- The snippet shown in email client inboxes
  • Template selection -- Load a template to pre-fill the body
  • Segment targeting -- Filter recipients by tags or signup source
  • Scheduling -- Send immediately or schedule for a future date/time
  • Sender overrides -- Custom from email and reply-to per campaign

Campaigns Tab

History of all campaigns (draft, scheduled, sent):

  • Campaign subject, status, send date, recipient count
  • Per-campaign analytics: open count, click count, unsubscribe count, bounce count
  • Drill-down to detailed campaign analytics with top clicked links and event timeline

Templates Tab

Reusable email template library:

  • Built-in templates -- Weekly digest, welcome, re-engagement, milestone, referral, survey
  • Custom templates -- Create your own with name, description, category, subject template, and HTML body
  • Professional HTML -- All built-in templates use responsive table-based HTML with the ArgoBox brand (gradient accents, glassmorphic styling)
  • Usage tracking -- Each template tracks how many times it has been used
  • Template categories -- digest, welcome, re-engagement, milestone, referral, survey

Automations Tab

Event-driven email workflows:

  • Trigger types -- welcome (new subscriber), or custom triggers defined in trigger_config
  • Configurable delay -- Send immediately or after N minutes
  • Template or custom body -- Link to a template or write inline HTML
  • Enable/disable per automation without deleting
  • Sent count tracking -- See how many emails each automation has triggered

Setup

1. Apply Database Migrations

Three D1 migrations must be applied in order:

Migration Purpose
0021_newsletter.sql Base tables: newsletter_subscribers (id, email, source, status, tags) and newsletter_campaigns (id, subject, body, type, status)
0022_newsletter_premium.sql Expands to full platform: double opt-in fields, engagement scoring, open/click counts, scheduling, segmentation, A/B testing, templates table, automations table, tracking events table
0023_newsletter_templates_pro.sql Upgrades all built-in templates to professional branded HTML. Adds template categories: re-engagement, milestone, referral, survey. Enables welcome automation with professional HTML

Migration files are in /migrations/.

2. Configure Environment / Settings

Newsletter settings are stored in Cloudflare KV (key: data:module:newsletter:config) and managed through the Settings page at /admin/settings/newsletter.

Setting Description
fromEmail Display name and email for outbound newsletters (e.g., ArgoBox <newsletter@argobox.com>)
replyTo Where subscriber replies are directed
unsubscribeSecret HMAC-SHA256 secret for generating secure one-click unsubscribe tokens. Changing this invalidates all existing unsubscribe links

The settings page includes a "Generate Random Secret" button for the unsubscribe secret.

3. Required Services

  • Cloudflare D1 -- Subscriber, campaign, template, automation, and tracking data
  • Cloudflare KV (ARGOBOX_CACHE namespace) -- Newsletter config storage + legacy subscriber fallback
  • Resend -- Email delivery (API key configured as RESEND_API_KEY environment variable)

API Endpoints

All endpoints are under /api/newsletter/. Admin endpoints require Cloudflare Access authentication.

Public Endpoints

Endpoint Method Description
/api/newsletter/subscribe POST Subscribe an email address. Accepts { email, source }. Returns success or duplicate status. Stores in D1 with KV fallback
/api/newsletter/unsubscribe GET One-click unsubscribe via HMAC token. Params: email, token. Verifies token, marks subscriber as unsubscribed
/api/newsletter/unsubscribe POST Form-based unsubscribe confirmation. Same token verification
/api/newsletter/track/open GET Tracking pixel endpoint. Params: cid (campaign ID), email. Records open event, returns 1x1 transparent GIF
/api/newsletter/track/click GET Click tracking redirect. Params: cid, email, url. Records click event, redirects to target URL

Admin Endpoints

Endpoint Method Description
/api/newsletter/subscribers GET List subscribers with pagination and search. Query params: page, limit, search, status
/api/newsletter/subscribers POST Create or update a subscriber. Body: { email, name?, source?, tags?, status? }
/api/newsletter/subscribers DELETE Remove a subscriber by email. Body: { email }
/api/newsletter/campaigns GET List campaigns with optional status filter. Query params: status
/api/newsletter/campaigns POST Create a new campaign. Body includes subject, body_html, segment filters, scheduling, A/B config
/api/newsletter/send POST Send a campaign to matching subscribers via Resend. Body: { campaignId }
/api/newsletter/templates GET List all email templates
/api/newsletter/templates POST Create or update a template. Body: { name, category, subject_template, body_html, ... }
/api/newsletter/templates DELETE Delete a template by ID. Body: { id }
/api/newsletter/automations GET List all automations
/api/newsletter/automations POST Create or update an automation. Body: { name, trigger_type, template_id, delay_minutes, ... }
/api/newsletter/automations DELETE Delete an automation by ID. Body: { id }
/api/newsletter/analytics GET Dashboard analytics: subscriber stats, growth chart, top campaigns, recent events. Query param: campaignId for per-campaign drill-down
/api/newsletter/export GET Download all subscribers as CSV
/api/newsletter/import POST Bulk import subscribers from CSV upload (multipart form)
/api/newsletter/digest POST Auto-generate a digest campaign from recent blog posts

Architecture

Three-Tier Structure

Tier 1: @argobox/newsletter (npm package)
  packages/newsletter/src/
    core.ts      -- Email builder, HMAC tokens, CSV import/export, validation
    types.ts     -- All TypeScript interfaces (Subscriber, Campaign, Template, etc.)
    adapters.ts  -- Standalone adapters (Resend sender, Node env, Bearer auth)

Tier 2: ArgoBox Adapters
  src/lib/newsletter/
    adapters/argobox.ts  -- D1 database queries, KV operations, Resend delivery
    settings.ts          -- KV-based config loading with 60s cache
    email-templates.ts   -- ArgoBox-branded HTML email templates

Tier 3: ArgoBox Integration
  src/pages/admin/newsletter.astro          -- Admin dashboard (6-tab SPA)
  src/pages/admin/settings/newsletter.astro -- Settings page
  src/pages/api/newsletter/*.ts             -- API route handlers
  modules/newsletter/module.json            -- Module manifest

Data Flow

  1. Subscriber signs up via public /api/newsletter/subscribe endpoint
  2. Stored in D1 newsletter_subscribers table (with KV fallback for legacy)
  3. Admin composes a campaign in the Composer tab, optionally using a template
  4. Campaign saved to D1 newsletter_campaigns table
  5. Send triggered via /api/newsletter/send -- queries matching subscribers, builds personalized emails with tracking pixels and click-tracked links, delivers via Resend
  6. Opens tracked via 1x1 pixel in /api/newsletter/track/open
  7. Clicks tracked via redirect in /api/newsletter/track/click
  8. Analytics aggregated from newsletter_tracking_events table, displayed in Dashboard tab

Database Tables

Table Purpose
newsletter_subscribers Subscriber profiles with engagement tracking (20 fields)
newsletter_campaigns Campaign definitions with A/B testing and segment config
newsletter_templates Reusable email templates with categories and usage counts
newsletter_automations Event-driven email workflows with trigger configuration
newsletter_tracking_events Open/click/unsubscribe events with campaign and subscriber linkage

Open Source Usage

The core logic is available as a standalone npm package for use outside of ArgoBox.

Installation

npm install @argobox/newsletter

Sub-path Imports

Import Contents
@argobox/newsletter Everything (barrel export)
@argobox/newsletter/core Pure functions: email builder, HMAC tokens, CSV, validation
@argobox/newsletter/adapters Standalone adapters: Resend sender, Node env, Bearer auth
@argobox/newsletter/types All TypeScript interfaces

Quick Example

import {
  buildNewsletterEmail,
  generateUnsubscribeToken,
  buildUnsubscribeUrl,
  buildTrackingPixelUrl,
} from '@argobox/newsletter/core';
import { createResendEmailSender } from '@argobox/newsletter/adapters';

// Build a newsletter email
const token = await generateUnsubscribeToken('reader@example.com', process.env.UNSUB_SECRET!);
const unsubscribeUrl = buildUnsubscribeUrl('reader@example.com', token);
const { html, text } = buildNewsletterEmail({
  subject: 'Weekly Homelab Digest',
  unsubscribeUrl,
  trackingPixelUrl: buildTrackingPixelUrl('campaign-1', 'reader@example.com'),
  posts: [
    { title: 'ZFS vs Btrfs', url: 'https://example.com/zfs', description: 'A real-world comparison' },
  ],
});

// Send via Resend
const sender = createResendEmailSender(process.env.RESEND_API_KEY);
await sender.send({
  from: 'newsletter@example.com',
  to: 'reader@example.com',
  subject: 'Weekly Homelab Digest',
  html,
  text,
  headers: { 'List-Unsubscribe': `<${unsubscribeUrl}>` },
});

Custom Adapters

Implement the EmailSender, EnvAdapter, or AuthAdapter interfaces to use your own email provider or authentication:

import type { EmailSender } from '@argobox/newsletter/types';

export function createSESEmailSender(region: string): EmailSender {
  return {
    async send(opts) {
      // Your AWS SES / Postmark / Mailgun implementation
      return { ok: true };
    },
  };
}

Runtime Compatibility

Works in Cloudflare Workers, Node 18+, Deno, and Bun. Core functions use only Web standard APIs (crypto.subtle, fetch).


Key Files

Path Purpose
packages/newsletter/ Standalone npm package (Tier 1 core + Tier 2 adapters)
packages/newsletter/src/core.ts Email builder, HMAC tokens, CSV, validation
packages/newsletter/src/types.ts All TypeScript interfaces
packages/newsletter/src/adapters.ts Resend sender, Node env adapter, Bearer auth
src/lib/newsletter/adapters/argobox.ts D1/KV database adapter for ArgoBox
src/lib/newsletter/settings.ts KV config loader with 60s cache
src/lib/newsletter/email-templates.ts Branded HTML email templates
src/pages/admin/newsletter.astro Admin dashboard (6 tabs)
src/pages/admin/settings/newsletter.astro Settings page
src/pages/api/newsletter/*.ts 13 API route files (16 endpoint methods)
modules/newsletter/module.json Module manifest
migrations/0021_newsletter.sql Base tables
migrations/0022_newsletter_premium.sql Full platform expansion
migrations/0023_newsletter_templates_pro.sql Professional template upgrade

Related Docs

  • Newsletter Signup -- Public-facing signup component and the original subscribe-only system
  • Open-Source Packages -- All publishable packages including @argobox/newsletter
  • Email -- The full email platform (separate from newsletter)
adminnewsletteremailcampaignssubscriberstemplatesautomationsanalyticstrackingresendd1