Guide

Automating appointment reminders with Salesforce Flow

A practical build for confirmations and reminders that stay right when appointments move: the data model, the two ways to schedule, and how to test it safely.

Key takeaways

  • Keep appointments on a record with a Date/Time start and a lookup to the person, then trigger everything from that record.
  • Either wait in Flow with a scheduled path and send at that moment, or send straight away with a future Send At time and let ConnectSMS hold the text.
  • Save the reminder's Message ID so a reschedule or cancellation can cancel it.
  • Build idempotency keys from the record ID and the start time, so saving twice never sends twice.
  • Don't ask customers to reply CANCEL or YES. Those are opt-out and opt-in keywords.

Plan the messages

Before opening Flow Builder, decide what the customer receives and when. Most appointment programs need four messages, and only one of them is scheduled:

MessageWhenHow
ConfirmationWhen the booking is savedSent immediately
Reminder24 hours before, or the morning ofScheduled
Change noticeWhen the time changesSent immediately; the old reminder is canceled and a new one scheduled
Cancellation noticeWhen the appointment is canceledSent immediately; the reminder is canceled

Send them all from one number that your front desk watches. Customers reply to reminders ("Can I come at 11 instead?"), and those replies should reach a person who can act on them.

Choose a data model

Option A: a custom Appointment object

A small custom object gives you full control and keeps the Flow simple. A typical design:

FieldTypePurpose
Start__cDate/TimeWhen the appointment starts
Contact__cLookup(Contact)Who to text
Status__cPicklist: Booked, Canceled, CompletedDrives the automation
Location__cTextWhere to go
Time_Label__cTextThe start time as the customer should read it
Reminder_Message_Id__cText(18)The scheduled reminder, so it can be canceled

It also makes reports such as Appointments tomorrow easy, which matters if you later want a daily list or outreach.

Option B: Salesforce Events

Events already hold a start time and a WhoId pointing to a Contact or a Lead, and they appear on the Salesforce calendar. Record-triggered flows run on Events too. The trade-offs: WhoId can be either object, so handle both; custom fields on Events are activity fields shared with Tasks; and recurring series and calendar-sync tools add cases to test. If you use Salesforce Scheduler or Field Service, appointments are ServiceAppointment records, and the same patterns apply.

Get the time right

Salesforce stores Date/Time values in UTC and shows them in each user's time zone. That makes one part easy and one part tricky.

  • When to send is easy. "24 hours before Start__c" is an exact moment. It's right wherever the customer happens to be.
  • What the text says is trickier. When automation turns a Date/Time into words, it formats it for the user the automation runs as, in their time zone and locale, not the customer's. If that user is set to your business's time zone and you only serve one, that's fine. Otherwise, fill a text field such as Time_Label__c when the appointment is booked, or store a Date field plus a Time field; Salesforce Time fields don't shift with time zones.
  • "9 AM the day before" needs the customer's time zone; "24 hours before" doesn't. Start with the simpler rule unless you already store each customer's time zone.

Option 1: a record-triggered flow with a scheduled path

This is the standard Salesforce approach, and it works with any SMS action.

  1. Create a record-triggered flow on your appointment object that runs when a record is created or updated, with the entry condition Status__c = Booked, set to run only when a record is updated to meet the condition requirements.
  2. Add a scheduled path based on Start__c, for example 1 day before.
  3. On the path, get the appointment again and check it's still booked and still at the time you expect. Don't rely on the wait alone.
  4. Send the text with Send Text Message, leaving Send At blank so it goes now.

Strengths: no limit on how far ahead the appointment is, and the text is written with the data as it is when the path runs. Weaknesses: the pending reminder lives in Salesforce's scheduled-path queue, where front-desk staff can't see it on the customer's message history, and changes depend on how Salesforce re-evaluates pending paths when the record changes. Check Salesforce's scheduled path considerations before relying on it.

Who the flow runs as. An immediate path runs as the user who saved the record. Scheduled paths don't; they typically run as the Automated Process user, so check in your org. Whoever it is needs permission to send: in ConnectSMS, either the ConnectSMS User permission set with Send access to the number, or ConnectSMS Automation with a number marked Available to automation. If your scheduled path's user can't be given that, publish a platform event from the path and send from a platform event–triggered flow whose running user is an integration user with ConnectSMS Automation.

Option 2: schedule the text with Send At

With ConnectSMS you can also schedule the reminder at the moment the appointment is saved. The Send Text Message action has an optional Send At input. ConnectSMS stores the message as Scheduled and sends it in the first 15-minute slot at or after that time, up to 35 days ahead.

In the flow's immediate path, after the record is saved, set these inputs:

InputValueNotes
Record ID{!$Record.Id}Needs your appointment object added in ConnectSMS Recipients, with a phone field such as Contact__r.MobilePhone. Or pass {!$Record.Contact__c} to text the Contact.
Template IDYour reminder templateMerge fields are filled from the record. Or use Message with Fill In Merge Fields.
Business NumberBlank, or your appointments lineBlank uses the automation default number.
Send At{!ReminderAt}A future time, at most 35 days ahead.
Idempotency Key{!ReminderKey}A new start time gets a new key; a second save doesn't.
Client ReferenceOptional, such as the appointment numberStored on the message, never sent.
FlowFormula resources
// Record-triggered Flow on Appointment__c, after save
// Entry: Status__c = 'Booked' AND (ISNEW() OR ISCHANGED({!$Record.Start__c}))

ReminderAt   (formula, Date/Time)
  {!$Record.Start__c} - 1

ReminderKey  (formula, Text)
  {!$Record.Id} & '-reminder-' & TEXT({!$Record.Start__c})

CanSchedule  (formula, Boolean)
  {!ReminderAt} > NOW() && {!ReminderAt} < NOW() + 35

The action returns Success, Message ID, Status (Scheduled), Scheduled For, and Error Code and Error Message when something is wrong. Save the Message ID in Reminder_Message_Id__c, and add a decision on Success so a failure is logged or routed to someone.

A few rules to design around:

  • Past times are refused. For a booking made less than a day ahead, the reminder time has already passed. The CanSchedule check lets you skip it or send a single confirmation instead.
  • 35 days is the limit. For appointments further out, combine both options: a scheduled path 30 days before the start makes the Send At call.
  • The text is filled in when it's scheduled. If the appointment details change, cancel the reminder and schedule a new one.
  • It's visible. The reminder shows on the record's message history with the time it will send, and staff can cancel it there too.

Write the message

Keep reminder wording in a ConnectSMS template rather than in the flow, so changing a sentence doesn't need a deployment. For an appointment object, a reminder template might read:

Hi {!Appointment__c.Contact__r.FirstName|there}, a reminder of your appointment at {!Appointment__c.Location__c|our office} on {!Appointment__c.Time_Label__c}. Reply here if you need to reschedule.

  • Fallbacks go after a vertical bar and are used when the field is empty: up to 80 characters, no braces.
  • Leave some fields without one. A blank field without a fallback blocks the send, and for automation the request is recorded as Blocked with the reason. For the appointment time, that's what you want: no reminder is better than "your appointment on ."
  • Preview it against a real appointment in the template editor before you activate it.
  • Keep it to one segment: straight quotes, no emoji, a short location. Why that matters.

Handle reschedules and cancellations

A reminder for the wrong time is worse than no reminder. When the start time changes or the appointment is canceled, cancel the pending text with the Cancel Scheduled Text Message action, which takes one input, Message ID.

FlowReschedule or cancel
// Start__c changed, or Status__c changed to 'Canceled'
Decision  Reminder_Message_Id__c is not blank?
  Cancel Scheduled Text Message
    Message ID   {!$Record.Reminder_Message_Id__c}
  Decision  Success?
    true   // the old reminder is now Canceled
    false  // NOT_CANCELLABLE: it was already handed to Twilio
Decision  Still booked?
  Send Text Message  // new Send At and a new Idempotency Key
  Update Records     Reminder_Message_Id__c = new Message ID
  • Cancellation works until the message is handed to Twilio. After that it returns NOT_CANCELLABLE, because a sent text can't be recalled; decide whether to send a correction.
  • The flow's running user must be allowed to cancel: the user who requested the message, a ConnectSMS admin, or someone with Send access to its number.
  • With the scheduled-path approach there's nothing to cancel in ConnectSMS; the check on the path does the work.

Replies, quiet hours and opt-outs

Replies

A reply to a reminder joins the conversation for that business number and appears in the ConnectSMS inbox for everyone with access to the number. Staff with Send access answer from the same number, and the conversation is linked automatically when exactly one Contact, or failing that one open Lead, has the customer's number.

ConnectSMS acts on opt-out and opt-in keywords and nothing else, so other replies are for people to read. That makes the wording of your prompt important. "Reply CANCEL to cancel" opts the customer out of texts, because CANCEL is a standard opt-out keyword, and "Reply YES to confirm" can opt someone back in. Ask customers to reply in their own words.

Quiet hours

If your admin turns on quiet hours, automated texts that fall inside them are held until quiet hours end, in the business time zone. A reminder scheduled for 7:00 AM with quiet hours ending at 8:00 AM goes at 8:00 AM, and Scheduled For shows the later time. Staff messages and replies are never delayed, so choose reminder times outside quiet hours.

Opt-outs

ConnectSMS checks opt-outs when the reminder is scheduled and again when it's due. If the customer has already opted out, Success is false with the error code OPTED_OUT. If they opt out after it was scheduled, the check at send time blocks it. How opt-outs work.

Test in a sandbox

When a sandbox is created or refreshed from production, ConnectSMS turns sending off in the copy automatically until an admin turns it on there, so a refresh can't start texting real customers. Before you turn it on, make sure the test records carry your team's own phone numbers, and consider a separate Twilio number for testing. Then work through the cases:

  • A booking two days out: the reminder shows as Scheduled with the right time.
  • Saving the booking again without changes: no second reminder.
  • Moving the start time: the old reminder is Canceled and a new one Scheduled.
  • Canceling the appointment: the reminder is Canceled and the notice sent.
  • A booking for tomorrow morning, whose reminder time has passed.
  • A booking more than 35 days out.
  • A test phone that has texted STOP: Success is false with OPTED_OUT.
  • A reminder inside quiet hours: Scheduled For shows when they end.
  • A reply from the test phone: it appears in the inbox.

Get Text Message Status returns the current status in a test flow, or check the timeline on the record. For every ConnectSMS action and input, see sending SMS from Salesforce Flow; for the front-desk side, see appointment texting.

Keep exploring

Try it now: every feature, free for 14 days

Put every customer text where your team already works.

Install ConnectSMS from AgentExchange, connect your Twilio account and give your team the numbers they should text from.

  • No credit card required
  • Listed on Salesforce AgentExchange
  • Then $120 per user per year
  • Runs on your own Twilio account

ConnectSMS is published by WorkBridge Solutions. Twilio bills your Twilio account directly for messaging, including during the trial.