Automated Renewal Reminders for AMC
By Prakash Panthi, Founder · Published September 6, 2026 · Updated September 15, 2026
A contract that lapses because the client simply forgot to renew — not because they decided to leave — is one of the most avoidable ways an AMC business loses recurring revenue. Automated reminders fix most of it, but a naive implementation creates its own problem: sending the same reminder every single day for a month straight.
The standard architecture
The reliable pattern for this is a cron job, not anything triggered by a web request — since there's no guarantee a staff member or client will visit the admin panel on the day a reminder needs to go out. A daily cron entry (commonly scheduled for early morning) invokes a standalone PHP script that:
- Queries the contracts table for anything expiring within a defined set of day-windows — 30, 15, 7, and 1 day out is a common tiering.
- Sends an email for each matching contract, typically via PHPMailer
over SMTP rather than PHP's built-in
mail()function, which is unreliable for anything beyond basic testing. - Optionally sends an SMS for the more urgent tiers — MSG91 is the standard choice for an India-focused business (REST API, widely documented PHP integration examples), with Twilio as the equivalent option for a more international client base.
A cron entry for this looks roughly like 0 8 * * *
php /path/to/reminder_cron.php — running once daily, early enough
that a same-day issue can still be handled before end of business.
The bug almost every first attempt at this has
A query like "expiry date is within 30 days" is true for 30 consecutive days in a row — which means a naive script sends the same reminder every single day for the entire window, not once at the moment it matters. This is the single most common mistake in building this feature, and it's an easy one to miss in testing since it only shows up as an annoyance days later, not an outright error.
The fix is to track state, not just recompute the condition fresh each
run: add a column like last_reminder_tier to the contracts
table, and only send a reminder when the newly computed tier (30, 15, 7,
or 1 day out) differs from what's already stored — updating that column
in the same operation as the send, so a contract only gets one email per
tier, not one per day within it.
Tiering and escalation
A sensible default tiering is 30/15/7/1 days before expiry, with urgency escalating as the date approaches — email only at the earlier tiers (30, 15 days), adding SMS at the closer, more urgent tiers (7, 1 day) where a client is less likely to be checking email regularly. This mirrors how subscription billing systems handle renewal notices generally: start quiet, get louder as the deadline nears.
Don't stop at the expiry date — add a grace period
A contract that reaches its expiry date without renewal usually isn't actually over from the client's perspective — they may still intend to renew and simply haven't gotten to it. Rather than silently stopping reminders at the exact expiry date, add a grace-period window (commonly 1-2 weeks past expiry) with its own distinct "reactivation" reminder, rather than treating a lapsed contract as immediately and permanently gone. This is the same concept subscription-billing systems call the "dunning" phase — recovering revenue from a lapse caused by oversight, not a deliberate decision to leave.
Why this is worth building properly, not as an afterthought
This isn't a minor convenience feature. Industry analysis of subscription and contract-based businesses attributes an estimated 20-40% of total churn to passive causes — lapses from inaction or oversight rather than a customer actively choosing to leave — making it one of the largest recoverable-revenue gaps a contract-based business has. For an AMC business specifically, a silently lapsed contract isn't just lost revenue — it's a piece of equipment that's now unmonitored until someone happens to notice, which is exactly the outcome AMC billing exists to prevent in the first place.
FAQ
Do I need SMS, or is email enough?
Email alone is usually enough for earlier reminders (30/15 days out), but adding SMS for the final, most urgent tiers (7/1 day) meaningfully improves the odds of actually reaching someone who doesn't check email daily — worth the added integration effort for the tiers where timing matters most.
What happens if the cron job itself fails to run one day?
Since the reminder logic is state-based (comparing the computed tier against what's stored, not "did we run yesterday"), a missed day doesn't break the sequence — the next successful run still catches any contract that crossed a tier threshold, even if a day was skipped. This is one practical benefit of tracking tier state in the database rather than relying on a strict daily schedule never failing.
Should reminders stop entirely once a contract has lapsed?
No — a short grace-period reminder captures renewals that were simply delayed rather than declined. Stopping entirely at the exact expiry date gives up on exactly the recoverable-revenue category (passive, oversight-driven lapses) that automated reminders are meant to address.
Available systems in this category
The system this guide was written for is not available for new purchases right now. These PHPGuru-developed systems cover related needs — check each page for exactly what it includes.
- Asset & Equipment Maintenance Log — Track equipment, log servicing, and never miss a due date in PHP
- Courier & Parcel Tracking System — Book parcels, update their status and give customers a public tracking page, in PHP
- Project & Time Tracker — Projects, tasks and start/stop timers with one running timer per person, in PHP