Skip to content
scsiwyg
sign insign up
get startedhow it worksmcpscsiblogcommunityapiplaygroundswaggersign insign up
โ† Making scsiwygยทNewsletter: From Zero to Send16 Apr 2026David Olsson

Newsletter: From Zero to Send

#scsiwyg#devlog#newsletter#email#building-in-public#pro

David OlssonDavid Olsson

Newsletter: From Zero to Send

scsiwyg pro members can send newsletters now. No dashboard, no drag-and-drop editor, no campaign builder. You compose a newsletter the same way you write a post โ€” in markdown, from your IDE โ€” and scsiwyg handles the rest: double opt-in, batch delivery, unsubscribe compliance, and delivery tracking.

This is a Pro feature. Here's what we built and why we built it this way.

What it does

A newsletter in scsiwyg is just a post with isNewsletter: true. It goes through the same markdown pipeline โ€” same rendering, same code highlighting, same Mermaid diagrams. The difference is what happens after you publish: instead of sitting on a page waiting for readers, it goes to their inbox.

The full flow:

Eight MCP tools handle the entire lifecycle:

ToolWhat it does
enable_newsletterTurns newsletter on for a site, sets sender name and email
compose_newsletterCreates a post marked as newsletter (draft state)
test_newsletterSends a test email to your own address
preview_newsletterReturns metadata, subscriber count, readiness status
send_newsletterGenerates a time-limited approval link (does not send directly)
get_subscribersLists subscribers with status breakdown
get_send_statsRecent sends, delivery counts, subscriber growth
remove_subscriberAdmin removal of a subscriber

The approval gate

We made a deliberate choice: send_newsletter does not send. It generates a 32-byte token and a 15-minute approval URL. You have to click the link to actually dispatch emails.

This exists because newsletters are irreversible. A typo in a blog post is a quick edit. A typo in 500 inboxes is permanent. The approval step is a 15-minute circuit breaker โ€” long enough to review, short enough that you don't lose context.

The approval endpoint works two ways: browser session auth (you click the link) or bearer token auth (for external platforms like AI Peers that manage their own approval layer).

Subscribe flow

When newsletter is enabled, a subscribe form appears on the blog index. Double opt-in:

  1. Reader enters email โ†’ subscriber created with status: pending
  2. Verification email sent immediately
  3. Reader clicks verify link โ†’ status: active, welcome email sent
  4. Every email includes a one-click unsubscribe link (RFC 8058 compliant)

Rate limited to 10 subscribe attempts per hour per IP. Duplicate handling: already active gets a message, pending gets a re-sent verification.

Delivery infrastructure

Emails go through Resend. Subscribers are batched in groups of 100. Each send is tracked individually via sendEvents โ€” every email gets a Resend ID, and webhooks update status as events come in:

  • email.delivered โ†’ records delivery timestamp
  • email.opened โ†’ records open timestamp
  • email.bounced โ†’ marks subscriber as bounced
  • email.complained โ†’ marks as unsubscribed (abuse protection)

The newsletter admin dashboard (Pro) shows per-send stats: sent, delivered, opened, clicked, with percentages. Subscriber drilldown shows individual status, verification dates, and activity.

How to use it

Enable newsletter on your site:

enable_newsletter(enabled: true, fromName: "My Blog", fromEmail: "noreply@coms.scsiwyg.com")

Compose and send:

compose_newsletter(slug: "april-update", title: "April Update", body: "# What we shipped\n\n...")
test_newsletter(slug: "april-update")
send_newsletter(slug: "april-update")

Then click the approval link. That's it.

What's next

Scheduled sends and subscriber segmentation are on the list. Right now every active subscriber gets every newsletter โ€” no filtering, no segments. That's fine for small lists. It won't be fine forever.

The newsletter feature ships with the same principle as everything else in scsiwyg: if you can do it from a terminal, you don't need a dashboard to do it.

Share
๐• Post