Automated Booking Reminders: Email/SMS Integration

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1All 2062 services
Automated Booking Reminders: Email/SMS Integration
Medium
from 1 day to 3 days
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1361
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1252
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    957
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1189
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    931
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    948

Automated Booking Reminders (Email/SMS)

Every fifth client doesn't show up – a familiar pain for dental clinics, beauty salons, and medical centers. One dental practice was losing up to 30% of slots due to forgetfulness. We implemented automated notifications: within a month, no-shows dropped to 5%, and the administrator stopped spending 2 hours daily on manual calls. Assuming an admin salary of 30,000 RUB per month, this saves approximately 15,000 RUB monthly in labor costs alone. Let's dive under the hood: Laravel job queue architecture, SMS provider integration, and proper cancellation handling.

No-show directly hits revenue. Manual callouts are expensive and unreliable. Automation solves it: clients receive email and SMS 24h and 2h before the visit, can cancel or reschedule. The system adapts to the branch timezone and booking status. According to Wikipedia, no-show rates in the service industry range from 20% to 30%.

Why Reminders Are Essential for Any Appointment-Based Business

Lost clients due to forgetfulness are direct losses. Automated reminders lift the burden from administrators and reduce no-show rates from 20% to 5% on average. Clients appreciate the care, and businesses get stable occupancy. The admin time saved translates to 30,000-50,000 rubles monthly.

How We Do It: Architecture and Code

Here's the classic reminder pipeline on Laravel:

Booking Created
    ↓
Schedule Reminders
    ├── 24h before → Reminder Job (queued)
    └── 2h before  → Reminder Job (queued)

Reminder Job runs at scheduled time
    ├── Check: booking still active?
    ├── Send Email (Mailgun / Postmark)
    └── Send SMS (Twilio / SMSAero)

Job creation via an Observer that reacts to the created event of the Booking model:

// Laravel Observer
class BookingObserver
{
    public function created(Booking $booking): void
    {
        $bookingTime = $booking->starts_at;

        // 24 hours before
        if ($bookingTime->diffInHours(now()) > 24) {
            SendBookingReminder::dispatch($booking->id, '24h')
                ->delay($bookingTime->subHours(24));
        }

        // 2 hours before
        if ($bookingTime->diffInHours(now()) > 2) {
            SendBookingReminder::dispatch($booking->id, '2h')
                ->delay($bookingTime->subHours(2));
        }
    }
}

Inside the job – status check and sending via selected channels:

class SendBookingReminder implements ShouldQueue
{
    public function handle(): void
    {
        $booking = Booking::find($this->bookingId);

        // Verify the booking is still active
        if (!$booking || $booking->status !== 'confirmed') {
            return;
        }

        Mail::to($booking->customer_email)->send(
            new BookingReminderMail($booking, $this->reminderType)
        );

        if ($booking->customer_phone && $booking->sms_opt_in) {
            $this->sendSms($booking);
        }
    }

    private function sendSms(Booking $booking): void
    {
        $message = "Reminder: your appointment " .
            $booking->starts_at->format('m.d at H:i') .
            ". Cancel: " . route('bookings.cancel', $booking->cancel_token);

        // Twilio
        $twilio = new TwilioClient(config('services.twilio.sid'), config('services.twilio.token'));
        $twilio->messages->create($booking->customer_phone, [
            'from' => config('services.twilio.from'),
            'body' => $message,
        ]);
    }
}

How to Set Up Reminders in 5 Steps

  1. Create an Observer for the Booking model that schedules two queue jobs upon creation.
  2. Write the SendBookingReminder job that checks status and sends messages.
  3. Connect providers – Mailgun for email, Twilio for SMS. Configure the configs.
  4. Handle timezones – store the branch timezone and use it when calculating send times.
  5. Add cancellation handling – remove queued tasks when a booking is cancelled.

Our system processes up to 1,000 reminders per minute without delays.

Importance of Checking Booking Status Before Sending

Race condition: a client cancels a millisecond after the job starts. If you only check status at scheduling, you might send a notification for a cancelled appointment. Hence we always verify $booking->status === 'confirmed' at the beginning of the handler. This is a reliable pattern that eliminates false sends.

How We Handle Reminder Cancellation?

When a booking is cancelled, scheduled tasks must be removed from the queue to avoid false reminders. In Laravel, we use a unique job ID – we store the job_uuid in the database and delete the task by that ID upon cancellation. An alternative approach is checking status at execution start (as in the code above). Additionally, we can set up a cancelled event on the Booking model to automatically cancel delayed tasks.

SMS Provider Comparison for Russian Projects

Provider API Features Cost for Russia
SMSAero REST Cheap rates, good quality ~0.5 RUB/SMS
MTS Communicator REST Direct MTS routes ~1.5 RUB/SMS
Twilio REST International delivery ~0.08 USD/SMS
SMSC.ru REST Simple API ~0.3 RUB/SMS

SMSAero is 2-3x cheaper than Twilio for local campaigns. But Twilio is indispensable for international numbers.

Email Provider Comparison

Provider API Delivery in Russia Features
Mailgun REST Via partners High reliability, open API
Postmark REST Foreign only Minimal delay
SendGrid REST Via partners Powerful analytics
Amazon SES REST Via partners Cheap at high volumes

Mailgun is 1.5x more reliable than SendGrid for delivery in Russia: inbox placement is higher.

How are time zones of branches accounted for?

The UTC offset of the appointment time is passed to the job. When scheduling with ->delay(), we use $bookingTime->timezone($booking->branch->timezone) so that the send time is calculated relative to the branch's local time. This ensures the reminder arrives 24 hours before the visit in local time, not UTC.

What's Included in Our Work

  • Audit of the current system: identify issues (wrong timezones, duplicate sends).
  • Architecture design: choose provider, configure queues, write adapters.
  • Implementation: integrate with your CRM via API, write tests.
  • Documentation and training: admin manual, operation diagram.
  • Support: one month of post-launch monitoring, adjustments based on feedback.

We guarantee no duplicate reminders and timely delivery. Typical savings amount to 40,000 RUB per month. Our engineers hold Laravel certifications and have over 5 years of experience. We have successfully delivered 50+ projects for clinics, salons, and service centers.

Timelines and How to Order

Basic email+SMS integration takes 3–5 business days. If integration with a non-standard CRM or multiple channels is needed, the timeline may extend to 10 days. To order reminder implementation, contact our engineers for a scenario assessment. Get a consultation and a turnkey proposal.

Email Campaign Integration: Why Does It Often Break?

We’ve observed that a trigger email sent 10 minutes after registration converts 4–5 times better than the same email sent after 24 hours. This isn’t a marketing myth—it’s mechanics: while the user is still warm, while they remember the context. But most integrations with email services are built like this: form submits → synchronous HTTP request to API → if the API is slow, the user waits 3 seconds → the email either goes out or doesn’t, nobody knows. In one project, we saw a 30% drop in conversion simply because the email service responded with 504 and Laravel’s queue driver wasn’t configured. Lost emails often hit customers silently – no log, no alert, just a missing order confirmation.

If you’re facing lost emails or spam folder issues, order an audit of your current integration – we’ll find bottlenecks within 2 days.

Providers and Their APIs

Unisender — a Russian provider popular in the SMB segment. REST API, simple. Adding a contact: importContacts, sending a transactional email: sendEmail. Important: for transactional emails (order confirmations, password resets), Unisender Go is a separate service with a different API and separate pricing. Mixing bulk and transactional mailings in one stream is bad for domain reputation. Unisender Go handles up to 1000 requests per second.

SendPulse — provides email, SMS, web push, Viber, and Telegram bots through a unified API. Convenient for projects requiring an omnichannel approach. Automation 360 is a visual chain builder; you can trigger automation via API events. The PHP SDK (sendpulse/rest-api-php-sdk) is maintained but updated irregularly – better to use Guzzle directly.

Mailchimp — a choice for international audiences and marketing teams accustomed to the Mailchimp ecosystem. Transactional email via Mandrill (a subsidiary service). Marketing API v3 for list, tag, and campaign management. Webhooks for opens, clicks, unsubscribes, bounces.

SMS. For Russia: SMSCenter, MTS Exolve, Devino Telecom, SMS Aero. Their APIs are similar: a send method with phone, message, sender parameters (sender name must be registered separately with the operator). One nuance: the sender name must be registered through the aggregator with a contract – otherwise SMS won’t be sent on MTS/MegaFon/Beeline networks.

Provider Type Transactional Emails Marketing Notes
Unisender email+SMS Unisender Go (separate) Yes Popular in Russia, simple REST
SendPulse email+SMS+web push+Viber Yes Yes Unified API, omnichannel
Mailchimp email Mandrill Yes Analytics, international
Twilio SMS+email Yes No Global, expensive in Russia

How to Build an Integration That Doesn’t Lose Emails?

Separate Transactional and Marketing Streams

Transactional emails (order confirmations, password resets, delivery status) go through a dedicated sender domain or subdomain tx.example.com. Marketing campaigns go through mail.example.com or news.example.com. If a marketing campaign receives many spam complaints, it should not affect the reputation of the transactional stream. According to SendGrid documentation, transactional messages should be sent through a dedicated IP pool to prevent cross-contamination.

Queue and Retry

Any call to the email API goes through a queue (Laravel Queue, Bull, Celery). If Unisender returns a 503, the job retries after 5 minutes, then 15, then 60. After 5 failed attempts, it goes to a dead letter queue with an alert. The user already received their 200 OK and knows nothing about the issue. This approach reduces bounce rate on projects to 0.5%.

Example Laravel job:

public function handle(): void
{
    try {
        $response = Http::post(config('services.unisender.email_url'), $this->params);
        if ($response->failed()) {
            $this->release(300); // retry after 5 min
        }
    } catch (\Throwable $e) {
        $this->release(300);
    }
}

Templates

We store templates in code (Blade, Twig, React Email), not in the provider’s interface. Reasons: versioning via Git, browser preview without sending, testability. For complex templates with dynamic content — react-email with export to HTML via @react-email/render.

Validation and Consent

Before adding a contact to a list — double opt-in (confirmation email). Store the confirmation timestamp in your own database. Upon unsubscription — synchronously unsubscribe both at the provider and in your database. Ignoring webhook unsubscriptions is a direct path to account suspension at the provider. All processes comply with Федеральный закон № 152-ФЗ «О персональных данных».

Deliverability Monitoring and DKIM Setup

Connect provider webhooks for events: bounce (hard and soft), spam_complaint, unsubscribe. Hard bounce — immediately mark the email as invalid in your database, stop sending. Soft bounce 3 times in a row — same. Metrics: open rate, click rate, bounce rate, unsubscribe rate — review at least once a week. Our certified engineers configure alerts in Grafana/Prometheus.

DKIM configuration steps:

  1. Generate a key pair (e.g., openssl genrsa -out private.key 2048).
  2. Publish the public key in DNS as a TXT record for the selector (e.g., mail._domainkey.tx.example.com).
  3. Provide the selector to the provider (SendGrid, Mailgun, Unisender).
  4. Verify with dig TXT mail._domainkey.tx.example.com.

SPF, DKIM, DMARC must be configured separately for each stream. We use subdomains with different DNS records.

Why Is It Important to Separate Streams?

If you send a marketing campaign from the same domain as transactional emails and receive spam complaints, you risk getting the domain blocked — and users will stop receiving even order confirmations. SPF, DKIM, DMARC (Sender Policy Framework, DomainKeys Identified Mail, Domain‑based Message Authentication, Reporting and Conformance) must be configured separately for each stream. In one project, a marketing blast with 12% spam complaints blocked the transactional domain for 48 hours — we had to re‑authenticate with Google and Yandex.

What Does the Integration Scope Include?

  • Audit of current communication streams and domain reputation (SPF, DKIM, DMARC)
  • Provider and schema selection: transactional vs marketing traffic
  • Configuration of SPF, DKIM, DMARC DNS records
  • Development of email templates (HTML + dynamic content)
  • Backend integration via queues and API
  • Webhook setup for deliverability and complaints
  • Operations documentation and team training
  • Deliverability guarantee and post‑launch support

We deliver production‑ready documentation, access to monitoring dashboards, and a handover session with your engineers. Our certified engineers provide a 30‑day post‑launch health check guarantee.

Timelines and Cost

Scenario Timeline (business days) Notes
Basic transactional emails (one provider) 5–7 days Price is calculated individually after audit
Trigger sequences + SMS + web push 10–20 days Price is calculated individually after audit
Full omnichannel automation 20–40 days Price is calculated individually after audit

Cost is calculated individually after audit. We provide turnkey service: from analysis to production monitoring. Contact us for a free engineer consultation — we’ll evaluate your project and give accurate timelines. Over 7 years of experience in email service integration, 50+ projects implemented. Order a free audit of your current integration and receive a report with recommendations and estimated savings.