Automated Appointment Scheduling and Booking using iCalendar Protocol
Tags: devops, beginners, webdev, node
Published: 2021-03-30 13:53:58

In this guide we will look at the **iCalendar Protocol** and how it is used in daily life for **appointment scheduling** and booking.

## Intro
The email industry has gone through many historical problems. Allowing users to schedule and book events using email was one of them. Back in 1998 the iCalendar protocol was invented to provide a standard interface for scheduling appointments and events by email. In a nutshell it's just a file sent/received by your email client (Gmail, Outlook, etc.). This file contains details about the event: status, organizer details, attendee details and useful addons like RSVP.

The example below illustrates iCalendar in action (on Gmail). Basically it's just a standard email with an attached event (invite.ics file) -- this allows Gmail to show a nice UI with the event's details: date, location, attendees and RSVP buttons (yes, maybe, no).

![icalendar for scheduling and booking events](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1de24w7hji0y29eq7zb.png)

## Integration
Using the iCalendar protocol is fairly simple, there exist many well-maintained libraries for most programming languages. We will be using NodeJS today.

The full GitHub code is found on [our repository here](https://github.com/Spurwingio/iCalendar-Integrations/). The file which contains all the logic is `index.js` which we'll dissect here.

### Architecture
Our simple application acts as a REST service with one single GET endpoint. We will refer to this endpoint as our WebHook. This means that external apps/services can make a GET request to our WebHook URL, which creates an iCalendar event and emails it to all attendees.

The endpoint URL will be like: `/appointment?name=Billy&email=billy@gmail.com`

The entire flow of our process can be visualized as such:
![appointment booking with icalendar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j07y6jeebcn3lh9ejl9z.png)

Flow analysis:
1. A client uses our front-end widget to book an appointment.
2. The Spurwing API receives and processes the client's request.
3. Upon success, the widget's code calls our WebHook.
4. The webhook creates an iCalendar event and emails the attendees.
5. Each attendee receives the email with RSVP options.

The flow above is actually a temporary workaround and insecure. Ideally, this flow should be simplified. The WebHook should be handled by a private service (not a public REST service). In our case it should be an add-on feature at the Spurwing API level, which is currently under construction:

![appointment booking with icalendar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7uh1lhyj2c9cx91kc69q.png)

### Implementation
Here we briefly analyze the NodeJS code structure. As mentioned before, please refer to our GitHub repository for the full code.

To configure this WebHook service, you need to create a file `config.js` (or rename it) and enter the following credentials:

```js
module.exports = {
  organizer: {
    name: '',      // organizer's name
    email: '',     // organizer's email
    smtp_pass: '', // email password (or app password)
  },
  attendee: {
    name: '',      // host's name
    email: '',     // host's email
  },
}
```

It's important to note that we provide an organizer and an attendee (a.k.a host) in this configuration. The organizer could be a `no-reply` company email or an email account used only for sending automated emails. This shouldn't be your actual email account.

The attendee/host is actually yourself; the person who is scheduling an appointment with the client (from the website). This may look strange and weird, but the organizer is an email account which is not included in the appointment. It's simply an account used for sending out emails (but not a part of the actual meeting). However the attendee/host is included in the meeting.

It took some time to figure this out myself, the reason is this: when we use Gmail/Outlook to manually schedule an event, the organizer is also the attendee/host -- you do not receive the RSVP email because your Email Service already puts the event in your calendar. But here we do not directly access our calendar, instead we utilize the iCalendar protocol to send an email to ourselves and the client. 

If you use the same email account for organizer and attendee/host, then you will not receive any email and will not be able to add it to your calendar. Because the iCalendar protocol assumes that your Email Service already does that for you.

Once you have configured these details you can use the code as is. But you should also make some changes to `index.js`, such as configuring the service PORT and email's title, subject, text/summary. These fields are marked with `// change` at the end of the line.

To launch this WebHook service you can use `node index.js` or PM2 (`ecosystem.config.js` is included).

## Calling the WebHook

To call your WebHook from front-end JavaScript you can use XHR/Ajax. I prefer using jQuery as such:

```js
// SpurwingHookURL = "https://YourSite.com/SpurwingHook/appointment"
if (SpurwingHookURL) {
    $.getJSON(SpurwingHookURL, {
        name,
        email,
        start: fixDateOffset(selectedSlot),
        end: fixDateOffset(D.appointment.end),
    }, function(resp) {
        console.log(SpurwingHookURL, resp)
    })
}
```

This creates a GET request with four URL parameters: client's name, email and the start/end time (ISO format) of the event.


## Conclusion
It's actually all quite simple and straightforward. The only counter intuitive part is that we need to use another email account for the organizer, and your personal email for the attendee/host part.

[iCalendar Integration Code](https://github.com/Spurwingio/iCalendar-Integrations/)

[Booking Widget Code](https://github.com/Spurwingio/Appointment-Scheduling-Widgets/tree/main/SimpleAppointmentScheduling)

And for more Scheduling, Booking and Calendar resources visit [Spurwing's Github profile](https://github.com/Spurwingio).

Enjoy!