How a testimonial request goes out
The collector only asks customers who are on the list. So the first job is making sure the list actually reflects who’s been happy lately. There are three ways a happy moment gets in: somebody types a row in the Drive sheet, somebody forwards a glowing email to a dedicated address, or a 5-star rating in your review tool pings a small endpoint. The first one is obvious. The other two exist because in real life nobody types a row in a sheet for the kind email they just read.
Key takeaways
- Three intake lanes feed one list: the Drive sheet, an inbox-forwarding lane, and a ratings webhook.
- Forwarded praise is read by Bedrock Haiku 4.5, which proposes a row for one-tap approval.
- The ratings lane is a Function URL: a 5-star rating posts a customer straight in as a candidate.
- One warm ask goes out at the right moment, then at most one gentle reminder — never a third.
- Asks respect quiet hours and a never-nag cool-down. No reply is treated as a polite no.
Three lanes into one list
Lane 1: the Drive sheet itself
The simplest lane. Open the list sheet in Drive, add a row, save. The columns are short: name, email, the moment that made them a candidate, the date of that moment, the rating (if any), and later the reply, the tidied quote, the permission state, and the publish state. A small Lambda — drive-sync — runs every fifteen minutes, exports the sheet as plain CSV via the Drive API, and writes it to s3://tc-list-source/list.csv if the sheet has changed since the last sync. The collector reads from S3, not Drive directly. That keeps Drive API calls predictable and gives you S3 versioning for free, so a bad bulk-edit can be rolled back in one click.
This lane covers the cases where you already know a customer was happy — the call that ended well, the handshake at the end of a project — and you can spend thirty seconds typing it in.
Lane 2: inbox forwarding (the lane most teams actually use)
Set up a dedicated inbound address — something like kudos@your-company.com — via Amazon SES. Anyone on the team forwards a kind email to that address and the collector takes it from there. SES writes the raw MIME to s3://tc-raw-mime/. The S3 PUT triggers a parser Lambda. The Lambda walks the MIME tree to the message body and pulls out the plain text of the forwarded note. There’s no document parsing here — praise arrives as email, so no Textract and no per-page charges.
Then a Bedrock Haiku 4.5 call reads the text and emits a structured row: the customer name, their email (from the original sender line), the moment type (set to “glowing reply”), and a one-line summary of what they liked. The model prompt is short: “Pull out who said this and a one-line summary. Return JSON only. Do not invent an email that isn’t in the message.” The output goes to a small Slack interactive message that pings the person who forwarded the email: the proposed row and three buttons — approve, edit, discard. On approve, a Lambda writes the row to the Drive sheet via the Sheets API. On edit, they get a fillable modal pre-populated with the proposal. On discard, the message is logged and the email moved to a discarded prefix in S3 for audit.
The reason every parsed row goes to a human first is simple: asking the wrong person for a testimonial — or getting their name wrong — is a worse outcome than the email never making the list at all.
Lane 3: ratings webhook
Many teams already collect star ratings — on Google, on a booking tool, in a post-job survey. When a 5-star rating comes in, there’s no reason to retype it. Lane 3 is a small Lambda Function URL that your review tool calls on each new rating. The Lambda checks the score; a 5-star (or 4-and-above, if you set it that way) rating with a contact attached is written straight onto the list as a candidate, with the rating and the date already filled in. A lower rating is ignored — this system only ever asks the people who were genuinely happy.
The webhook is the most hands-off of the three lanes. Once it’s wired up, happy customers flow onto the list without anyone lifting a finger, and the never-nag cool-down (covered below) makes sure nobody gets asked twice in a short window.
How the ask actually goes out
Once a candidate is on the list and has cleared the cool-down, the daily tick decides on a move (the full move logic is the next post’s territory; here’s the short version). On the first ask, the collector reads the matching template from the voice doc, fills in the customer’s name and the moment, and sends one short, warm email through SES with a single link to a reply form. If there’s no reply after a set gap (default 5 days), it sends exactly one gentle reminder. If that also gets no reply, the candidate is closed quietly — no reply is treated as a polite no, and a decline buys a full year of silence. Every send respects quiet hours and the holiday calendar, so an ask never lands at 2am or on a public holiday.
The whole point of capping it at one reminder is trust. A business that asks once, kindly, and then stops is a business people are happy to hear from. A business that asks five times is one people mute.
Next post: how a customer’s reply gets tidied into a short, clean quote — without changing a word of what they meant.
All posts