Part 1 of 7 · Newsletter composer series ~5 min read

A newsletter composer on AWS for a few dollars a month

A small business has more to share than it ever gets around to sending. The two blog posts that went up this month and nobody told the list about. The new feature that quietly shipped. The big client win the team is proud of. The case study that’s been sitting in a folder. A newsletter is the easiest way to stay top of mind with the people who already like you — and it’s the first thing that slips, because writing one from a blank page on a busy Friday is nobody’s favorite task. This post walks through the design of a small composer that gathers the week’s updates, drafts a clear, friendly issue in your voice, and hands it to you to approve, edit, or skip before anything sends.

Key takeaways

  • Three sources for items: a Drive sheet anyone can add to, a feed lane for your blog, and an inbox forwarding lane.
  • Every weekly run ends in one of four moves: skip, draft, redraft, or ready for review.
  • The draft is grounded only in the items you gathered, and every claim links back to a source.
  • The owner is always the last step — approve, edit, or skip. Nothing sends without sign-off.
  • Designed on AWS for about $2.80/month at typical small-business volume.

The whole system on one page

Before any code, here’s the shape of what we’re designing.

System architecture: three sources, three pieces inside AWS At the top, three external boxes in a row. Far left, "Weekly items" — a Google Drive sheet where anyone on the team can drop a win or a product note, plus a feed lane that watches your blog's RSS for new posts and an inbox forwarding lane that turns a forwarded update into a proposed item. Centre, "Voice and rules" — a Drive folder with a voice doc that holds your tone, your standard sign-off, and example issues, plus a rules doc covering how many items make an issue, the send day, the reviewer, and quiet hours. Far right, "Owner and list" — the owner who reviews every draft and approves, edits, or skips it, and the subscriber list the approved issue is sent to. Each connects via an arrow to the AWS account container below. Weekly items have an outgoing arrow into AWS. Voice and rules feed in to ground every draft. The owner receives the full draft with a flag on anything unsourced and three buttons — approve, edit, or skip; the list receives only an approved issue. Inside the AWS account are three components in a row, mirroring the layout above. On the left, the Item intake — receives items from each source, tidies forwarded updates via Bedrock, and writes the cleaned item into the pool. In the middle, the Composer — runs weekly; reads the item pool; counts the fresh items; drafts the issue grounded in those items via Bedrock; picks one of four moves: skip, draft, redraft, or ready. On the right, the Sender — posts the draft to the owner for review, respects quiet hours and the cooling-off window, and only sends an approved issue to the list via SES. Internal arrows flow left to right. A note at the bottom reads: every issue is drafted only from gathered items — and nothing is sent until the owner approves it. Weekly items sheet, feed, inbox Voice and rules tone, threshold, reviewer Owner + list review, then send items in grounds draft to review AWS account Item intake tidy, normalize, add to the pool Composer picks one of four: skip, draft, redraft, ready Sender review then send, respects quiet hours items draft Every issue is drafted only from gathered items — nothing sends without the owner’s OK.
Fig 1. Three sources outside, three pieces inside AWS. Items flow in from a Drive sheet, a feed lane, and an inbox forwarding lane. The Composer runs weekly and picks one of four moves. The Sender shows the draft to the owner and only mails an approved issue to the list.

What you set up once (the outside)

  • Weekly items. A Google Sheet in a Drive folder, one row per item: a short title, a one-line note, a category (blog post, product note, win, event, other), a link, and the date it happened. Anyone on the team can drop a win or a product note in here. New items also flow in from two other lanes covered in Part 2 — a feed lane (the composer watches your blog’s RSS feed and proposes a row for each new post) and an inbox-forwarding lane (forward an update to a dedicated address and the composer proposes a row for one-tap approval).
  • A voice and rules folder. Two short Google Docs in a Drive folder. The voice doc holds your tone, your standard greeting and sign-off, a few example past issues, and a short list of things to never say. This is what keeps the draft sounding like you and not like a robot. The rules doc covers how many fresh items make a worthwhile issue (default three), which day the issue sends, who reviews it, the quiet hours, and the cooling-off window between approval and send.
  • Owner and list. The owner reviews every draft. The draft lands with the full issue, a flag on anything the model couldn’t tie to a source item, and three buttons — approve, edit, skip. The subscriber list is the people who opted in; only an approved issue is ever sent to them.

What runs on every run (the inside)

  • The item intake. Three sources feed the pool. The Drive sheet is the canonical store. New items can also be added via the feed lane (a small sync Lambda checks your blog’s RSS every hour and proposes a row for each new post) and the inbox forwarding lane (forward an update to updates@your-company.com, the composer uses Bedrock Haiku 4.5 to tidy it into a clean title and one-line note, then drops a one-tap approval card in the team’s Slack to confirm before the row is added).
  • The composer. Runs once a week, the morning before the send day. Reads the item pool. Counts the fresh items added since the last issue. Compares against the threshold in the rules doc. Picks one of four moves. Skip: too few fresh items — tell the owner why, send nothing. Draft: enough items — call Bedrock Sonnet 4.6 to write the issue, grounded strictly in those items and the voice doc. Redraft: a self-check found a claim with no source — rewrite once to ground it. Ready: the draft passed its checks — hand it to the owner for review. The heavy writing is one Bedrock call per issue, not per item.
  • The sender. Posts the finished draft to the owner for review (Slack message or email) with the full issue and the approve/edit/skip buttons. On approve, it waits out a short cooling-off window (default 30 minutes, so a typo caught after the fact can still be pulled), then sends the issue to the subscriber list through SES outbound, respecting quiet hours. Every run, every action, and every send writes a row in DynamoDB so the trail is clear. A monthly summary writes a short note: issues sent, open rate if available, items that never made it in.

In plain words

It’s Thursday morning. Over the past week your blog published two posts, the team closed a nice deal with a regional client, and a small feature shipped. Three of those landed in the item pool automatically (the blog posts via the feed lane, the feature via a forwarded note); someone typed the client win into the sheet. The composer runs, sees four fresh items, and drafts a friendly issue: a warm intro, a short paragraph on each item with a link, and your usual sign-off. It checks its own work, finds every line traces back to an item, and posts the draft to you in Slack with three buttons. You read it, fix one phrase you’d say differently, tap Approve. Thirty minutes later the issue goes out to your list. Nobody wrote it from a blank page, and nothing went out that you hadn’t read.

The cost of running this is about $2.80 a month at SMB volume. The cost of not running it is the list that hears from you twice a year, the wins nobody outside the building knows about, and the slow drift of an audience you worked hard to earn.

Design rules that shaped every decision

  • Every issue is drafted only from gathered items — the composer never invents news. Every claim links back to a source.
  • Four moves, always. Skip, draft, redraft, ready. There is no fifth.
  • The owner is the last step. Approve, edit, or skip. Nothing sends without a human signing off.
  • Quiet hours and a cooling-off window are respected. A send is hard to undo; the design slows it down on purpose.
  • Too few items means skip, not pad. A thin issue trains people to stop opening you.
  • Every run and every action is logged. Ask next year why an issue did or didn’t go out and the trail answers.

Why this shape

Most teams write a newsletter in one of three ways: someone blocks an afternoon when they remember, a marketing tool with a blank template waits to be filled, or it never happens. The afternoon works until the afternoon gets eaten — and the weeks it gets eaten are the busy weeks, which are exactly the weeks worth writing about. The blank template is a chore, not a system; it tells you to write but does none of the writing. And “never” is how a hard-won audience quietly forgets you exist.

The setup above keeps your updates in a sheet the team already touches, but adds a small system that gathers them every week and does the first draft for you — grounded only in what actually happened, in your voice, with the links already in. It skips weeks that aren’t worth sending instead of padding them. It hands you a finished draft you can ship in a tap or fix in a minute. And it never, ever sends on its own. The composer does the part you dread; you keep the part only you should own.

The next four posts walk through each piece in turn: how a newsletter gathers the week’s updates, how an issue gets drafted, how a draft reaches the owner, and how an issue gets approved and sent. One diagram per post. A cost breakdown and a final engineering reference at the end.

All posts