Service Reminders on Microsoft 365
The same standard, for a trade business that lives in Microsoft 365: installed equipment as a list, dates worked out from a schedule list, reminders from Outlook, and each yes written back to the job system once.
Used by
- Office Manager
- Microsoft 365 Administrator
- Service Coordinator
How to get this live in your business
The temptation in SharePoint is a NextDue column, filled in once and sorted by. That is the one thing this plan leaves out. The date is worked out by the daily flow from a Schedule list, so changing the schedule moves every date and nobody edits one. The rest is lists, four flows, and one unique column that stops a second yes making a second job.
In short
What this is
A build plan for the Next Service standard on Microsoft 365. Six lists, four flows, and a booking request written into the job system you already run.
The core rule
Flow 2 reads Assets and Schedule every morning and works each date out. There is no due-date column to go stale when the schedule changes.
What it does not do
No flow picks a time slot or a price, and no message says what a warranty covers. A person books every request in the job system.
The hard part
Claiming the BookingRequests row before calling the job system, so a second yes or a retried flow finds it and writes nothing.
Take the spec to Claude, ChatGPT or Copilot. The sentence to paste is one click away.
Want the whole thing by email?
This paper, plus the rest of the library. One click to stop them.
1. Before you start
Read the Next Service build standard first. It defines its objects, and the lists below are those objects with SharePoint types on them. Shared conventions are in building the standards on Microsoft 365.
Decide how finished jobs get in. If your job system (ServiceM8, Simpro, Fergus, Jobber or AroFlo) has a connector or a webhook, Flow 1 triggers on a job marked complete. If not, a daily export into a list works. Tradify has no public API, so a Tradify business imports by hand and books each yes by hand.
Then write the Schedule list before anything else: one row per equipment type you install or service, with the months between services. Base it on the manufacturer’s instructions or your own advice. An asset whose type has no row is an exception, not a guess.
2. The lists, with their columns
For your developer. Show the fields for your developer
Site: ServiceReminders
LIST Assets (one row per piece of equipment, from the finished job)
AssetId Text indexed, UNIQUE, REQUIRED
CustomerId Text indexed, REQUIRED
SourceJob Text indexed. the job it was taken from
EquipmentType Text indexed. matches a Schedule row, or it is an exception
Make Text
Model Text
Serial Text
InstalledOn DateTime
LastServicedOn DateTime
WarrantyMonths Number as written on the job; blank means no warranty reminder
Exception Choice none | missing_install_date | missing_model
| missing_equipment_type | no_schedule
LIST Schedule (the written rule, one row per type)
EquipmentType Text indexed, UNIQUE, REQUIRED
ServiceMonths Number REQUIRED
ChangedBy Person
ChangedOn DateTime
LIST Customers
CustomerId Text indexed, UNIQUE, REQUIRED
CustomerName Text
Mobile Text
Email Text
ConsentSms Boolean what they agreed to, from your record
ConsentEmail Boolean
LIST Reminders (append only)
Asset Text lookup to Assets
ReminderKey Text indexed, UNIQUE. AssetId + Kind + DueOn + Stage
Kind Choice service | warranty
Stage Choice reminder | follow_up
DueOn DateTime as worked out at send time, kept as the record
Channel Choice sms | email
Body Note
SentAt DateTime
ReplyText Note their words, exactly
Outcome Choice none | yes | stop | unclear
unclear goes to a person
LIST OptOuts (no flow clears a row)
CustomerId Text indexed, UNIQUE
Said Note their words, exactly
ReceivedAt DateTime
LIST BookingRequests
RequestKey Text indexed, UNIQUE. AssetId + DueOn: one per date
Asset Text lookup to Assets
CustomerId Text indexed
ReplyText Note
JobNumber Text from the job system, once written
BookedBy Person the person who set the time
There is no NextDue column on Assets, on purpose. A stored date is the one that goes stale when the schedule changes.
There is no TimeSlot or Price column on BookingRequests either. A person books the time and prices the work in the job system.Unique values on Reminders.ReminderKey hold check 5: a second run on the same day cannot add a second reminder for the same date. Unique RequestKey on BookingRequests holds check 11: the second yes fails at SharePoint before the job system is touched.
3. Every rule, and what enforces it
| The rule | Enforced by | How |
|---|---|---|
| The equipment is taken from the finished job, as recorded | Flow 1, Assets.SourceJob | Flow 1 copies type, make, model, serial, dates and warranty term from the completed job, and skips a job whose number is already a SourceJob. |
| A missing install date, model or type goes to a person | Flow 1 and Flow 2, Assets.Exception | Either flow sets Exception and posts the asset to a Teams channel. Flow 2 skips any asset whose Exception is not none. |
| Due dates are worked out from the schedule, never typed in | Schedule list; no NextDue column | Flow 2 adds the Schedule months to LastServicedOn, else InstalledOn, every run. Editing a Schedule row moves every date of that type. |
| Already booked means no reminder | Flow 2, the job system connector | Before each reminder Flow 2 asks the job system for open jobs on that asset, and skips it if there are any. |
| Only on a channel the customer agreed to, and a stop is for good | Customers consent columns, OptOuts | Flow 2 checks OptOuts and the consent columns before every send. Flow 3 writes OptOuts on STOP. No flow deletes from it. |
| A yes becomes one booking request, with no time and no price | Flow 4, BookingRequests.RequestKey, unique | Flow 4 creates the BookingRequests row first; if it already exists the flow ends. Only then does it create the job and post the job number to Teams. |
4. The four flows
For your developer. Show the fields for your developer
FLOW 1 Finished job to asset
trigger a job marked complete (connector, webhook or daily import)
logic job number already a SourceJob -> stop
create or update the Assets row from the job, as recorded
no InstalledOn, Model or EquipmentType -> Exception, post to Teams
never fill a gap from the make, or type a due date.
FLOW 2 Daily reminders
trigger every morning, 8am
logic per asset with Exception none:
Schedule row for the type? none -> no_schedule, post to Teams
service due = (LastServicedOn or InstalledOn) + ServiceMonths
warranty due = InstalledOn + WarrantyMonths, only if set
per date inside the lead time and not past:
open job on the asset in the job system -> skip
OptOuts has the customer -> skip
no ConsentSms and no ConsentEmail -> no_consent, post to Teams
create Reminders row (ReminderKey unique) -> send
a reminder with no reply after the follow-up days:
one follow_up row (unique key) -> send
never send a second reminder or a second follow-up for a date.
FLOW 3 A reply arrives
trigger a new SMS reply or an email to the reminders mailbox
logic write ReplyText on the Reminders row, exactly as received
STOP or unsubscribe -> OptOuts row, Outcome stop
yes, or the booking link -> Outcome yes, run Flow 4
anything else -> Outcome unclear, post to Teams
never reply to the customer on its own.
FLOW 4 One booking request
trigger called by Flow 3, or the booking link
logic create BookingRequests row, RequestKey = AssetId + DueOn
it already exists -> stop
create the job in the job system against customer and asset
write JobNumber back, post it to Teams to be booked
never set a time slot or a price.Flow 4 claims the SharePoint row before it calls the job system, because the job system does not deduplicate for you. A flow that writes the job first and the row second makes two jobs the day the first call times out and retries.
5. The order to build it in
- Create the six lists from the schema, with the unique columns set.
- Write the Schedule list, then build Flow 1 and prove an asset with no install date lands as an exception.
- Build Flow 2 sending to a test mobile only, and prove changing a Schedule row moves the dates.
- Build Flow 3, and prove STOP writes OptOuts and an unclear reply reaches Teams.
- Build Flow 4 against the job system, and prove two YES replies leave one job.
6. Four traps specific to this build
A NextDue column, because it is easier to sort
It is right on the day it is filled in and wrong the day the schedule changes. Work the date out in the flow, and sort a view on a calculated value if you must.
Letting Copilot fill a missing model or warranty term
A plausible model or a usual five-year term is a guess written into the record. Leave it blank, raise the exception, and let a person check the unit.
Writing the job before claiming the row
Power Automate retries a step that times out. If the job is created first, the retry creates a second one. Claim the unique row first.
Warranty wording that sounds helpful
"Your repair is covered until..." is a statement about the customer's rights. The message states the expiry date on your record and nothing else.
7. Where the automation stops
- Booking the time and pricing the work for every booking request.
- Writing and changing the Schedule list.
- Fixing any asset with a missing install date, model or type.
- Answering any reply Flow 3 marks unclear, and taking anyone off OptOuts, which happens only if they ask.
The pass test. Change the hot water row in Schedule from twelve months to six and run Flow 2: every hot water date moves, and nobody edited one. Add a test customer to OptOuts: they get nothing. Put your own mobile on a test customer with a unit inside the lead time, reply YES to the reminder, then YES again: one BookingRequests row and one job in your job system. A few minutes on your own tenant.