Part 5 of 7 · Shipping notifier series ~5 min read

How a late delivery gets caught

An order was supposed to arrive Tuesday. It’s Wednesday morning and the status still says out for delivery. What happens? The honest answer is “three things, in order.” This post walks through what the notifier does when an order passes its expected date without arriving — warn the customer, alert the owner, log the delay — and how the order list, the send history, and the audit trail all stay in sync.

Key takeaways

  • Three things on a delay: warn the customer (calm heads-up), alert the owner (so a human can act), log the delay.
  • Each step updates the order list via the Sheets API and writes an audit row.
  • A delay marks the order so the customer warning is sent once, not on every check.
  • The delay check is bounded — one customer warning per delay, with owner re-alerts capped.
  • The whole flow is plain Python; the rules doc holds the expected-delivery windows.

Three things on a delay

Three things that happen on a late delivery A diagram showing one input on the left flowing into three action paths that all converge on an audit box. Far left: an "Order past its date" box showing the key facts — order number, expected date, days late, last known status. The notifier detected the order passed its expected delivery date with no delivered status. The middle column shows the three things that happen. Branch one, Warn customer: composes a calm heads-up from the delayed template — what's known, a new rough expectation, the tracking link — and sends it once via SES outbound, respecting the customer's unsubscribe. Branch two, Alert owner: emails the owner named in the rules doc with the order number, the days late, and the last known status, so a person can chase the carrier; owner re-alerts are capped so a stuck order doesn't spam the owner daily. Branch three, Log delay: marks the order delayed in the list via the Sheets API and writes the delay to the send history so the customer warning isn't repeated on the next check. The right side shows the convergence: every one of the three actions writes a row to the sn-audit DynamoDB table with timestamp, order id, action, and notes. A note at the bottom: the customer hears once, the owner can act, and the trail is complete — a late delivery never slips by silently. Order past its date order, date, days late [Warn] [Alert] [Log] Action 1 Warn customer • Calm delayed template: what’s known + tracking • Sent once via SES • Respects unsubscribe Action 2 Alert owner • Email owner: order, days late, last status • Re-alerts are capped so it won’t spam daily Action 3 Log delay • Mark order delayed in the list (Sheets API) • Record the send so it isn’t repeated Audit trail DynamoDB sn-audit timestamp · order_id action · days-late notes The customer hears once, the owner can act, and the trail is complete — a delay never slips by silently.
Fig 5. Three things on a late delivery, three different effects. Warn the customer with a calm heads-up. Alert the owner so a human can chase the carrier. Log the delay so the customer isn’t warned twice. Every action writes to the audit trail.

How a delay gets spotted

The notifier knows each order’s expected delivery date — either set per order in the list, or worked out from the carrier and shipping method using the windows in the rules doc (“standard ground: 5 business days; express: 2”). On each check, for any order that isn’t yet delivered, the notifier compares today’s date against the expected date. If the order is past it, the move is delayed.

A small grace setting in the rules doc (default one day) keeps the notifier from crying wolf on a parcel that’s a few hours behind. A delivery that’s expected by end of Tuesday and arrives Wednesday morning is normal; the grace window absorbs it. Only orders genuinely past their window get flagged.

Action 1: warn the customer (the calm heads-up)

The first thing that happens is the customer hears about it — from you, before they have to ask. The sender composes the delayed template: what’s known (“your order is taking a little longer than expected”), a new rough expectation if one can be worked out, and the tracking link so they can see for themselves. The tone is calm and honest — it doesn’t over-promise a new date the carrier hasn’t confirmed.

This warning goes out once per delay, not on every check. The moment it’s sent, the notifier records it in the send history, so the next check sees the delayed warning already went out and doesn’t repeat it. And it still respects the unsubscribe: a customer who opted out of updates won’t get the warning, though the owner alert below still fires.

Action 2: alert the owner (so a human can act)

A customer warning tells the customer the order is late. It doesn’t fix anything. The second thing that happens is the owner named in the rules doc gets an email with the order number, the days late, the last known status, and the tracking link — everything they need to call the carrier or open a claim. The point is to put a human on it early, while there’s still time to do something, rather than waiting for the customer to complain.

Owner re-alerts are capped. A parcel can sit stuck in a depot for days, and the owner doesn’t need a fresh email every 30 minutes about the same stuck order. The rules doc has a configurable owner_realert_days setting (default two). After the first alert, the owner is re-alerted at most that often until the order is delivered or resolved. This is the same care the customer warning gets: say it once, clearly, then stay quiet until something changes.

Action 3: log the delay (so nothing slips)

The third thing is bookkeeping, and it’s what keeps the whole flow honest. The notifier marks the order’s status as delayed in the order list via the Sheets API, so anyone looking at the sheet can see which orders are running late. It records the customer warning and the owner alert in the sn-sends history so neither is repeated. And it writes an action: delayed row to sn-audit with the order, the days late, and a short note.

If the order later gets delivered — the carrier finally scans it — the next check sees the delivered status, sends the delivered update (which doubles as the “it finally arrived” close), and the delay is resolved. The audit trail keeps both rows: the day it was flagged delayed, and the day it arrived. The monthly summary in Part 6 reads those rows to report how many orders ran late and how late they were on average.

Every action is logged, every delay is accounted for

The sn-audit table records every delay flag, customer warning, and owner alert with the timestamp, the order, and the days late. If a customer ever asks “why didn’t anyone tell me?” — or a teammate asks “did we warn them?” — the answer is one lookup away. The trail is the only memory the next person has when they pick up a stuck order someone else was handling.

This kind of accounting matters most for the orders that go wrong, which are exactly the ones a busy team is most likely to lose track of. A happy order needs no memory; a late one needs all of it.

Next post: the cost breakdown. The whole pipeline above runs in coffee-money territory at SMB volume; Part 6 explains exactly where the dollars go and why it’s less than you’d guess.

All posts