Trevor PaughSystems engineer
Trevor PaughProject Chronicles

Chronicles / Kongomax

Moderation email, live

Milestone

When a guestbook entry is waiting, the owner now gets an email with one-click Publish and Hide links, so moderating no longer means running SQL. Sent through Cloudflare's send_email binding from a separate Worker, with Resend as the fallback. Five slices, and a live test that passed end to end today.

The guestbook’s moderation queue worked from day one but nobody was told when it filled. Approvals happened when the owner remembered to look, and then happened in SQL.

The design

Email on Cloudflare’s free tier is possible through the Email Routing send_email binding, which can send to verified addresses. That fits a one-recipient alert exactly. The binding is used from a separate Worker rather than the site’s Pages Functions, to keep the site’s own code free of mail logic and the sending identity separate. If the binding fails, a Resend fallback sends the same message.

The goal was never just the notification. Each mail carries the entry text and two links, Publish and Hide, each single-use, so the owner moderates from the inbox. Links in the entry text are defanged before they go into the mail.

Five slices, 2026-09-29 to today

  • M1 to M3. The Worker and binding, the queue check, and the message itself.
  • M4. Privacy wording. Two wordings were offered for the form and the docs; the owner picked the one that says plainly that the moderation mail carries the entry text and that the links are single-use.
  • M5. The switch to live, and a record of how it went.

Going live

The owner did the production side by hand: the mail address and the moderation secret were set as production-only secrets, with nothing on preview, and the mail switch flipped on in KV. The first lesson came immediately: a Pages secret only reaches a running Worker after a fresh production deployment, so the deployment had to be redone before the mail could send. That is now a numbered step in the deploy runbook.

A rate-limit rule went in front of the site and the guestbook endpoints at the same time, and was verified from outside by watching requests start to get refused.

The live test: one entry posted, one mail received, both links worked, a second click on a handled entry answered “Nothing to do”, and no mail at all with the switch off. The test rows were deleted afterwards; two older held entries were resolved by hand. The one complaint was the wait for the mail scanner, which stays in the test steps, documented.