Weekly Newsletter
A Plunk campaign created and sent automatically every time the weekly batch publishes.
Every batch publication triggers a Plunk campaign with a summary of the week's products. The subscriber list is managed by Plunk, not by your app database.
Who receives it
Everyone who submitted their email via /newsletter (single opt-in) becomes a Plunk contact with subscribed: true. The weekly cron calls Plunk's campaign API, and Plunk selects the subscribed audience automatically.
There's no double opt-in. The signup handler at app/newsletter/ sends a welcome email immediately on submission.
When it's sent
Inside the weekly-batch cron (app/api/cron/weekly-batch/route.ts):
- The cron publishes a new batch and recomputes dofollow flags
- It then queries the previous batch (the one launched last week) and builds the newsletter from that data
- Creates + sends a Plunk campaign using the
weekly-newsletter.tsxtemplate - If
PLUNK_SECRET_KEYis missing, the campaign step is skipped silently
Which products make it in
Selection from the previous batch, matching the promises on the public /pricing page:
| Tier | Inclusion rule |
|---|---|
| Highlight | All of them. Guaranteed newsletter mention. |
| Boost | All of them. Guaranteed newsletter mention. |
| Free | Top N by vote count, where N = dofollow_top_n setting (default: 3) |
Order of appearance in the email: Highlights first, then Boosts, then Frees — each group sorted by vote count descending. The template tags Boosts with ⚡ and Highlights with ★ badges automatically.
The same dofollow_top_n setting drives both the dofollow promotion rule and the free-tier newsletter rule, so the two stay aligned. Change it in /admin/settings → schedule.
If you want a different rule (e.g., "top 10 free regardless of tier limit"), edit the selection block in app/api/cron/weekly-batch/route.ts.
The template
emails/weekly-newsletter.tsx is a React Email component. It renders:
- Header: site logo + week number
- Each product (in the order passed by the cron): thumbnail, name, tagline, tier badge, link to the product page
- CTA button "See all launches"
- Footer with unsubscribe
Testing locally
bun scripts/send-test-newsletter.tsThe script renders the current week's batch with WeeklyNewsletterEmail and sends a test via Plunk to the address in TEST_EMAIL (default placeholder until you set your own).
Preview the HTML
bun run email:devThis runs React Email's dev server from emails/. Open the browser preview, edit files, see changes live.
Managing subscribers
Because subscriber state lives in Plunk, not Postgres:
- Adding contacts: they submit
/newsletter→plunk.track()marks them subscribed - Unsubscribing: link in every email footer → Plunk's default unsubscribe handler (managed server-side by Plunk)
- Exporting: use Plunk's dashboard CSV export
- Removing: Plunk dashboard
If you want the list in your own DB, you'd need to add a subscribers table and toggle it yourself.
Tweaking timing
The newsletter goes out when the weekly cron runs. There's no separate "newsletter" cron. Adjust the schedule in your cron provider (see Cron Jobs).
Disabling the newsletter
To stop automated sends without removing the subscribe page:
- Remove the Plunk campaign call inside app/api/cron/weekly-batch/route.ts
To remove the subscribe page entirely:
- Delete
app/newsletter/ - Remove navigation links