Repository navigation
Send the weekly AutoJack newsletter (off until enabled) - #15
jack-arturo wants to merge 1 commit into
Conversation
Compose the previous Monday–Sunday posts into an issue that matches the welcome email, and mail confirmed Resend contacts in batches. The weekly cron stays off until Settings → Newsletter enables it. Co-authored-by: Jack Arturo <info@verygoodplugins.com>
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 47d9dbb58b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| foreach ( $slice as $index => $email ) { | ||
| $result = minimalcode_newsletter_deliver_one( $state, $email ); |
There was a problem hiding this comment.
Honor unsubscribes before delivering queued recipients
When a subscriber unsubscribes after the recipient list is captured but before their batch runs, the unsubscribe handler updates Resend, but this loop still sends to the saved address without checking its current status. With batches spread across cron requests, that interval can be substantial. A stubbed execution of the unsubscribe update followed by batch processing confirmed that the code still posts an email to the unsubscribed address. Recheck subscription status before delivery or maintain a suppression mechanism that queued batches consult.
Useful? React with 👍 / 👎.
| update_option( 'minimalcode_newsletter_active', $state, false ); | ||
| minimalcode_newsletter_process_batch( $plan['week_id'] ); |
There was a problem hiding this comment.
Prevent a new issue from overwriting an unfinished send
If an issue is still queued when another week's send starts—for example, a manual Sunday-night send followed by the Monday automatic slot—the per-week claim allows both runs, but this unconditional update replaces the only active state with the newer issue. Remaining callbacks for the old week then return because their week ID no longer matches, leaving its remaining subscribers unsent and its claim permanently marked sending. Refuse or defer a new issue while another week is active, or store active state separately for each week.
Useful? React with 👍 / 👎.
What was already there
The weekly issue never went out because nothing in this repo, or in the signup worker, collects posts and sends them.
Signup lives in the theme, the list does not.
inc/newsletter.phpplusNewsletterSignupinassets/js/theme.js. It POSTs{ email, company }tohttps://news.autojack.ai/subscribe. Aside, footer, and the mid-postajn-boxall use that endpoint. The old Fluent Snippet is gone; the theme owns the markup.autojack-newsletteron the Very Good Plugins account (scripteacb2b8feee74f8b870b4be12d594f2b, last deployed 2026-08-20). That source is not in this repo. It only implementsPOST /subscribe,GET /confirm, andGET /unsubscribe.NEWSLETTER_AUDIENCE_IDon the worker).https://api.resend.com), fromAutoJack <newsletter@news.autojack.ai>. Notwp_mail, and not an SMTP plugin.unsubscribed: true(pending) and sends the confirm mail. Confirm flipsunsubscribedtofalseand sends the welcome HTML from the worker’semailShell(paper#f3efe6, hot#e3ff04, Georgia masthead, AutoJack portrait, Berlin footer). Unsubscribe flips the flag back totrue. There is no separate “confirmed” column: confirmed meansunsubscribed === false. Pending and unsubscribed addresses aretrue.What this adds
The digest is a theme module, next to the form, because the posts live in WordPress.
inc/newsletter-digest.phpis pure (window, plan, HMAC tokens, HTML/text).inc/newsletter-weekly.phpwires WP-Cron or Action Scheduler, Resend, Settings → Newsletter, andwp minimalcode newsletter.The worker stays the system of record for signup, confirm, and the welcome mail. Weekly mail uses the same audience and the same HMAC unsubscribe tokens (
NEWSLETTER_CONFIRM_SECRET). The visible link andList-Unsubscribepoint at/newsletter/unsubscribe/on the site, which PATCHes the Resend contact and acceptsPOSTfor one-click (RFC 8058). The worker only implements GET, so the weekly issue cannot one-click through it.Each issue is one email per confirmed address (no shared To/Cc), with title, excerpt, and link per post, plus the welcome header and footer. Plain text is sent alongside HTML. A week with no posts is skipped and recorded. The same week cannot be claimed twice. Sends run in batches of 10, half a second apart, then the next batch 45 seconds later. One recipient’s error is logged and the rest continue. HTTP 429 pauses the batch. A partial run is marked sent so the successes are not mailed again; if everyone failed, the claim is released so Send now can retry. The log stores date, post ids, recipient count, and failures (failure addresses stay in an admin-only option).
Automatic sending ships off. Merging this does not email anyone. Enabling the toggle arms the next slot; it does not send the current week. Send now is a separate button (and
wp minimalcode newsletter sendasks unless--yes). Test sends go to one address, are prefixed[test], and do not claim the week.CI/GITHUB_ACTIONSrefuses every Resend call unlessMINIMALCODE_NEWSLETTER_ALLOW_SENDis set. Tests never load the sender.Schedule and how to turn it on
Default slot is Monday 08:00 in the site timezone (Settings → General). Weekday and time are editable. The window is the previous complete Monday 00:00 through Sunday 23:59:59, so a Monday morning send covers the week that just ended.
Scheduling uses
wp_schedule_single_eventonminimalcode_newsletter_weekly, or Action Scheduler’sas_schedule_single_actionwhen that plugin is loaded — not both. After each run the next slot is queued. If the slot was missed while the feature was already on, it is caught up for 18 hours. A slot from before the toggle was enabled is not caught up.WP-Cron only runs when something hits WordPress. On a quiet Monday the issue waits. On the server, every five minutes:
or
wp cron event run --due-now.To enable, copy the worker’s env into
wp-config.php(do not commit them):The secret must be the worker’s
NEWSLETTER_CONFIRM_SECRETso tokens match. Then Settings → Newsletter, check Email confirmed subscribers every week, and save. Preview is on that screen (wp minimalcode newsletter previewprints the same HTML). The list is only queried at send time, and only that audience or an explicit segment — never every contact on the Resend account.Set the site timezone to
Europe/Berlinif it is not already; 08:00 is the site clock, not a hardcoded Berlin clock.Preview
Rendered by
minimalcode_newsletter_render_html()for the week of 2 Nov 2026 (Mon–Sun before this Monday): the four posts that were actually on the log. Unsubscribe target is the preview token, so it does not change anyone’s subscription. Nothing was sent.Weekly issue for 2 Nov 2026
Subject:
This week on drunk.support — 4 new posts.Tests
tests/newsletter-weekly.phpcovers the default-off flag, the Mon–Sun window, the Monday 08:00 slot, the worker HMAC vector, confirmed-only filtering, empty-week skip, duplicate-week skip, batching, CI refusal, List-Unsubscribe, and HTML escaping. No network..github/workflows/test.ymlrunsphp -land the existing theme tests on pull requests. The deploy workflow is unchanged and still only runs onmain.To show artifacts inline, enable in settings.