The appointment reminder that would have arrived after the appointment
A quiet hours rule that is right for marketing texts is wrong for reminders. What happened on the first live run, why the fix belongs upstream, and the second bug it uncovered.
- build log
- automation
- n8n
- appointments
- reminders
- testing
I added appointment reminders to the free workflow pack tonight. The first live run sent a reminder that would have arrived after the appointment it was reminding about.
That is worth writing down, because it is not a typo and it is not a bad line of code. It is two correct rules meeting each other.
The two rules
Every outbound text in this system goes through one send path. One place decides whether a message may go out, applies the opt-out list, adds the STOP footer, logs it, and enforces quiet hours. If a message lands between 8pm and 8am, it gets parked until the morning.
That rule is right. Nobody wants a marketing nudge at 2am, and a business number that sends them gets reported and eventually blocked.
The second rule is that a reminder goes out a set number of hours before the appointment. Twenty four hours before, and again two hours before.
Now book a 7am job.
The two hour reminder is due at 5am. Quiet hours park it until 8am. The customer gets reminded at 8am about a 7am appointment.
Why the send path cannot fix it
The send path does not know there is an appointment. It knows there is a message and a phone number. Deferring is the safest thing it can do with what it has.
So the fix belongs upstream, in the workflow that actually knows when the job is.
The reminder now works out its send time against quiet hours before it waits. A reminder that falls inside quiet hours moves to the moment quiet hours end. If that moment is not before the appointment, the reminder is dropped entirely. Then the workflow tells the send path not to defer it again, because the decision was already made by the part of the system that had the appointment time in front of it.
One rule, written down so I do not undo it later: a reminder that cannot be useful is not sent.
That also settles some smaller cases. Book something three hours out and the day before reminder has nowhere to go, so it never fires. Two reminders that would land within five minutes of each other are treated as one.
The second bug, which was quieter and worse
When the workflow correctly suppressed that duplicate reminder, the branch that suppressed it just ended. Nothing wrong on the surface. Except the follow up row in the database stayed marked as running, with no execution left alive to ever close it.
A follow up stuck open is not cosmetic. It is what the morning brief counts when it tells the owner how many follow ups are running. It is what the inbound router looks at when a customer texts back.
The fix is a tidy step that both suppressed branches run into. It closes the row only if it is still active, so a follow up that a customer already stopped by replying keeps that status instead of being overwritten by a generic finished.
The part I actually care about
Neither of those came from reading the code. Both came from pointing the thing at a real phone number at nine at night and watching what happened.
AI will write you the happy path in an afternoon. It will not tell you that your reminder arrives after the appointment, because that requires knowing what the message is for.
Where it is
The workflows are free and public, MIT licensed, with the full test log next to them, including the checks that are not covered yet.
github.com/mikematthewsai/n8n-lead-response
Fifteen workflows: missed call capture, the follow up cadence, inbound routing with STOP and START, quote chasing, invoice reminders, a 7am owner brief, and now appointment reminders. Everything stops the moment a person replies.