# Customize Scheduler email for your app

Source: https://developer.nylas.com/docs/cookbook/workflows/scheduler-booking-email/

Scheduler sends booking confirmations for you, and you can't change their wording or branding. An application-level workflow replaces them with your own HTML, using one template that applies to every user of your product.

This recipe covers the whole booking lifecycle: confirmation, reschedule, cancellation, pending approval, and reminder. If each of your customers needs their own branding, use [Customize Scheduler email for each user](/docs/cookbook/workflows/scheduler-email-per-user/) instead.

![A branded booking confirmation email showing the meeting title, time in the recipient's timezone, duration, join link, attendee list, and a reschedule button](/_images/workflows/booking-created.png)

## How do I replace the Scheduler confirmation email?

Create a template, point an application-level workflow at it, then turn off Nylas's own email on the Scheduler configuration. The workflow fires for every grant in the application, so one template covers every user.

Start with the template. Set `engine` to `handlebars` explicitly, because the API default is `mustache` and mustache can't call the `formatDate` helper you need for times.

```bash
curl -X POST 'https://api.us.nylas.com/v3/templates' \
  -H "Authorization: Bearer $NYLAS_API_KEY" -H 'Content-Type: application/json' \
  -d '{
    "name": "Booking confirmed",
    "engine": "handlebars",
    "subject": "Confirmed: {{booking_info.title}}",
    "body": "<html>…</html>"
  }'
```

`body` is a JSON string, so every quote and line break in the HTML needs escaping. Rather than escaping by hand, let `jq` build the request from the template file:

```bash
jq -n --rawfile body booking-created.html \
  '{name: "Booking confirmed", engine: "handlebars",
    subject: "Confirmed: {{booking_info.title}}", body: $body}' \
| curl -X POST 'https://api.us.nylas.com/v3/templates' \
    -H "Authorization: Bearer $NYLAS_API_KEY" -H 'Content-Type: application/json' \
    -d @-
```

Then the workflow. `delay` is in minutes and `0` sends immediately.

The `from` address decides who the confirmation appears to come from. Omit it and the message sends through the host's own grant, so the guest sees it arrive from the host's real address, in the same thread as their other correspondence, with replies landing in the host's inbox. That needs no domain setup, only mail send scopes on the grant. Set `from` and it sends through [transactional send](/docs/v3/getting-started/transactional-send/) on a domain you registered, which gives every host the same branding. The [Workflows overview](/docs/cookbook/workflows/#which-sender-should-the-workflow-use) compares both.

For booking confirmations the host's own address is often the better choice, because a confirmation that looks personal gets replied to and a no-reply one doesn't.

```bash
curl -X POST 'https://api.us.nylas.com/v3/workflows' \
  -H "Authorization: Bearer $NYLAS_API_KEY" -H 'Content-Type: application/json' \
  -d '{
    "name": "Booking confirmed",
    "trigger_event": "booking.created",
    "template_id": "<TEMPLATE_ID>",
    "delay": 0,
    "is_enabled": true,
    "from": { "email": "bookings@yourdomain.com", "name": "Your Company" }
  }'
```

Drop the `from` line entirely to send from the host's mailbox instead. Everything else stays the same.

Repeat for each of the 5 booking triggers with its own template. `booking.rescheduled` and `booking.reminder` drop 4 fields that `booking.created` carries, and `booking.cancelled` has no `booking_ref`, so one shared template throws on whichever trigger lacks a field it references.

## How do I stop Nylas sending its own email?

Set `disable_emails: true` on the Scheduler configuration. Two fields control this independently, and your choice depends on whether guests also need the calendar provider's invitation.

| `disable_emails` | `notify_participants` | Messages the guest receives |
| --- | --- | --- |
| `false` | `false` | Nylas Scheduler email plus your workflow email |
| `true` | `false` | Your workflow email only |
| `true` | `true` | Your workflow email plus the Google or Microsoft calendar invitation |

Choose `notify_participants: true` when guests need a calendar reply button and a `.ics` attachment, which an HTML email can't provide. The provider sends that invitation from the organizer's own address rather than from Nylas, so it won't carry your branding. Microsoft grants ignore `notify_participants` and always notify, so the workflow-only setup isn't achievable on Microsoft.

```json
{
  "event_booking": {
    "title": "Meeting with ${invitee}",
    "booking_type": "booking",
    "disable_emails": true,
    "notify_participants": false,
    "reminders": [{ "type": "webhook", "minutes_before_event": 30 }]
  },
  "scheduler": {
    "additional_fields": {
      "notify_individually": {
        "label": "Notify individually",
        "type": "metadata",
        "required": false,
        "default": "true"
      }
    }
  }
}
```

`reminders` with `type: "webhook"` is what makes `booking.reminder` fire, and without it that trigger never runs. Use `booking_type: "organizer-confirmation"` for `booking.pending`, which also requires `scheduler.organizer_confirmation_url` or the request returns `400`. Updating a configuration uses `PUT` and replaces the whole object, so send the existing configuration back with your changes rather than a partial body.

## How do I address each guest by name?

Set `notify_individually` on the booking. Nylas then sends one message per participant and populates `recipient.email`, `recipient.first_name`, and `recipient.last_name` for each. By default it sends a single message to all participants, leaving `recipient` undefined so any template referencing it fails to render.

The field has to be declared on the [configuration](/docs/reference/api/configurations/) first, as shown above. Passing it on the [booking](/docs/reference/api/bookings/) alone returns `400 Additional field 'notify_individually' not found in configuration`.

```json
{
  "additional_fields": { "notify_individually": "true" },
  "start_time": 1790182800,
  "end_time": 1790184600,
  "participants": [],
  "guest": { "name": "John Smith", "email": "john@example.com" }
}
```

A booking with a guest named John Smith and an organizer named Nick then produces 2 messages from one template, reading `Hi John,` and `Hi Nick,`.

## How does the template work?

The template is ordinary HTML with `{{variable}}` placeholders filled from the event payload. Four parts do the real work.

**The greeting guards two levels.** `recipient` is absent whenever `notify_individually` is off, and present but unnamed when a participant has no display name. The renderer throws on a missing parent, so a single guard isn't enough.

```handlebars
{{#if recipient}}{{#if recipient.first_name}}Hi {{recipient.first_name}},{{else}}Hi there,{{/if}}{{else}}Hi there,{{/if}}
```

**The time resolves per recipient.** `booking_info` is identical in every copy of a message and only `recipient` changes between them, so one timezone expression would give every recipient the same zone. `lookup` works as a nested expression, which is enough to pick a zone per person.

```handlebars
{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}
  {{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}
{{else}}
  {{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}
{{/if}}{{/if}}{{/if}}
```

That resolves in 4 steps: the recipient's own timezone, then `guest_timezone`, then `organizer_timezone`, then UTC. `guest_timezone` is only set when the guest supplies one and is an empty string otherwise, which `formatDate` would silently treat as UTC, so the `{{#if}}` skips it when empty. `organizer_timezone` carries the configuration's `event_booking.timezone`, and if that's empty too, `formatDate` uses UTC.

Supply the per-recipient dictionary in the booking request, because the configuration's `default` value isn't applied to the payload. Email addresses are valid field keys.

```json
"additional_fields": {
  "notify_individually": "true",
  "host@yourcompany.com": "America/Chicago",
  "guest@example.com": "America/New_York"
}
```

One booking with a host in `America/Chicago` and a guest in `America/New_York` then produces `1:00 PM EDT` for the guest and `12:00 PM CDT` for the host, from the same template. Leave the guest out of the dictionary and they get `organizer_timezone` instead, because `guest_timezone` is empty on bookings made through the API.

**Optional fields are wrapped.** `location` arrives as an empty string on many bookings, so the Where row is wrapped in `{{#if booking_info.location}}` and disappears cleanly rather than leaving a dangling label.

**The locale is a variable.** `formatDate` takes a timestamp, an IANA timezone, a [Luxon token string](https://moment.github.io/luxon/#/formatting?id=table-of-tokens), and a locale, and all 4 accept variables. Passing `booking_info.guest_language` renders `miércoles 23 septiembre 2026` for `es` and `mercredi 23 septembre 2026` for `fr` with no extra work.

## The complete template

This is the `booking.created` template from the screenshot above. The other 4 booking triggers follow the same structure with their own fields.

```html [schedulerAppTemplate-booking.created]

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Your meeting is confirmed</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;
      line-height: 1.6;
      color: #333333;
      margin: 0;
      padding: 0;
      background-color: #f9fbfe;
      font-size: 16px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      text-align: center;
      padding: 20px 0;
    }

    .content {
      background-color: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .detail-label {
      color: #666666;
      font-size: 14px;
      padding: 6px 16px 6px 0;
      vertical-align: top;
      white-space: nowrap;
    }

    .detail-value {
      padding: 6px 0;
      vertical-align: top;
    }

    .footer {
      text-align: center;
      padding: 20px 0;
      color: #666666;
      font-size: 14px;
    }

    @media only screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }

      .content {
        padding: 20px !important;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <img src="https://brand.nylas.com/assets/site_images/Nylas-Logo_Horizontal-Blue.png" alt="Nylas Logo"
        style="max-width: 150px;" />
    </div>

    <div class="content">
      <h1 style="margin-top: 0; color: #1A1A1A;">Your meeting is confirmed</h1>

      {{#if recipient}}{{#if recipient.first_name}}<p>Hi {{recipient.first_name}},</p>{{else}}<p>Hi there,</p>{{/if}}{{else}}<p>Hi there,</p>{{/if}}

      <p>
        <strong>{{booking_info.title}}</strong> is booked. The details are below,
        and the invitation is already on your calendar.
      </p>

      <hr style="border: 0; border-top: 1px solid #eeeeee; margin: 20px 0;" />

      <h2 style="color: #4D4D4D; font-weight: 500;">Meeting details</h2>

      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
        <tr>
          <td class="detail-label">When</td>
          <td class="detail-value">
            {{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" "en" }}{{/if}}{{/if}}
          </td>
        </tr>
        <tr>
          <td class="detail-label">Duration</td>
          <td class="detail-value">{{booking_info.duration}} minutes</td>
        </tr>
        {{#if booking_info.location}}
        <tr>
          <td class="detail-label">Where</td>
          <td class="detail-value"><a href="{{booking_info.location}}" style="color: #0D6EFD;">{{booking_info.location}}</a></td>
        </tr>
        {{/if}}
        <tr>
          <td class="detail-label">Who</td>
          <td class="detail-value">
            {{#each booking_info.participants}}{{name}} &lt;{{email}}&gt;{{#unless @last}}<br />{{/unless}}{{/each}}
          </td>
        </tr>
      </table>

      <div style="text-align: center; margin: 30px 0;">
        <a href="{{booking_info.participant_rescheduling_url}}"
          style="background-color: #0D6EFD; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Reschedule</a>
      </div>

      <p style="font-size: 14px; color: #666666; text-align: center;">
        Can no longer make it?
        <a href="{{booking_info.participant_cancellation_url}}" style="color: #0D6EFD;">Cancel this meeting</a>.
      </p>
    </div>

    <div class="footer">
      <p>© 2026 <a href="https://www.nylas.com/" style="color: #0D6EFD;">Nylas</a></p>
      <p style="font-size: 12px; color: #999999; margin-top: 4px;">
        Booking reference: {{booking_info.event_id}}
      </p>
    </div>
  </div>
</body>

</html>


```

```html [schedulerAppTemplate-booking.rescheduled]

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Your meeting moved</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;
      line-height: 1.6;
      color: #333333;
      margin: 0;
      padding: 0;
      background-color: #f9fbfe;
      font-size: 16px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      text-align: center;
      padding: 20px 0;
    }

    .content {
      background-color: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .detail-label {
      color: #666666;
      font-size: 14px;
      padding: 6px 16px 6px 0;
      vertical-align: top;
      white-space: nowrap;
    }

    .detail-value {
      padding: 6px 0;
      vertical-align: top;
    }

    .footer {
      text-align: center;
      padding: 20px 0;
      color: #666666;
      font-size: 14px;
    }

    @media only screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }

      .content {
        padding: 20px !important;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <img src="https://brand.nylas.com/assets/site_images/Nylas-Logo_Horizontal-Blue.png" alt="Nylas Logo"
        style="max-width: 150px;" />
    </div>

    <div class="content">
      <h1 style="margin-top: 0; color: #1A1A1A;">Your meeting has moved</h1>

      {{#if recipient}}{{#if recipient.first_name}}<p>Hi {{recipient.first_name}},</p>{{else}}<p>Hi there,</p>{{/if}}{{else}}<p>Hi there,</p>{{/if}}

      <p><strong>{{booking_info.title}}</strong> has been rescheduled. The new time is below and your calendar has already been updated.</p>

      <hr style="border: 0; border-top: 1px solid #eeeeee; margin: 20px 0;" />

      <h2 style="color: #4D4D4D; font-weight: 500;">Meeting details</h2>

      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
        {{#if booking_info.old_start_time}}<tr><td class="detail-label">Previously</td><td class="detail-value"><span style="color: #999999; text-decoration: line-through;">{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.old_start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.old_start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.old_start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.old_start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.old_start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.old_start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.old_start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}</span></td></tr>{{/if}}
        <tr><td class="detail-label">Now</td><td class="detail-value">{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}</td></tr>
        <tr><td class="detail-label">Duration</td><td class="detail-value">{{booking_info.duration}} minutes</td></tr>
        {{#if booking_info.location}}<tr><td class="detail-label">Where</td><td class="detail-value"><a href="{{booking_info.location}}" style="color: #0D6EFD;">{{booking_info.location}}</a></td></tr>{{/if}}
        <tr><td class="detail-label">Who</td><td class="detail-value">{{#each booking_info.participants}}{{name}} &lt;{{email}}&gt;{{#unless @last}}<br />{{/unless}}{{/each}}</td></tr>
      </table>
      <div style="text-align: center; margin: 30px 0;"><a href="{{booking_info.participant_rescheduling_url}}" style="background-color: #0D6EFD; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Reschedule again</a></div>
      <p style="font-size: 14px; color: #666666; text-align: center;">Can no longer make it? <a href="{{booking_info.participant_cancellation_url}}" style="color: #0D6EFD;">Cancel this meeting</a>.</p>
    </div>

    <div class="footer">
      <p>&copy; 2026 <a href="https://www.nylas.com/" style="color: #0D6EFD;">Nylas</a></p>
      <p style="font-size: 12px; color: #999999; margin-top: 4px;">
        Booking reference: {{booking_info.event_id}}
      </p>
    </div>
  </div>
</body>

</html>


```

```html [schedulerAppTemplate-booking.cancelled]

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Your meeting was cancelled</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;
      line-height: 1.6;
      color: #333333;
      margin: 0;
      padding: 0;
      background-color: #f9fbfe;
      font-size: 16px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      text-align: center;
      padding: 20px 0;
    }

    .content {
      background-color: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .detail-label {
      color: #666666;
      font-size: 14px;
      padding: 6px 16px 6px 0;
      vertical-align: top;
      white-space: nowrap;
    }

    .detail-value {
      padding: 6px 0;
      vertical-align: top;
    }

    .footer {
      text-align: center;
      padding: 20px 0;
      color: #666666;
      font-size: 14px;
    }

    @media only screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }

      .content {
        padding: 20px !important;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <img src="https://brand.nylas.com/assets/site_images/Nylas-Logo_Horizontal-Blue.png" alt="Nylas Logo"
        style="max-width: 150px;" />
    </div>

    <div class="content">
      <h1 style="margin-top: 0; color: #1A1A1A;">Your meeting was cancelled</h1>

      {{#if recipient}}{{#if recipient.first_name}}<p>Hi {{recipient.first_name}},</p>{{else}}<p>Hi there,</p>{{/if}}{{else}}<p>Hi there,</p>{{/if}}

      <p><strong>{{booking_info.title}}</strong> has been cancelled and removed from your calendar.</p>{{#if booking_info.cancellation_reason}}<p><strong>Reason:</strong> {{booking_info.cancellation_reason}}</p>{{/if}}

      <hr style="border: 0; border-top: 1px solid #eeeeee; margin: 20px 0;" />

      <h2 style="color: #4D4D4D; font-weight: 500;">Meeting details</h2>

      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
        <tr><td class="detail-label">Was scheduled for</td><td class="detail-value">{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}</td></tr>
        <tr><td class="detail-label">Duration</td><td class="detail-value">{{booking_info.duration}} minutes</td></tr>
        <tr><td class="detail-label">Who</td><td class="detail-value">{{#each booking_info.participants}}{{name}} &lt;{{email}}&gt;{{#unless @last}}<br />{{/unless}}{{/each}}</td></tr>
      </table>
      <div style="text-align: center; margin: 30px 0;"><a href="{{booking_info.participant_rescheduling_url}}" style="background-color: #0D6EFD; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Book a new time</a></div>
      <p style="font-size: 14px; color: #666666; text-align: center;">You don't need to do anything else.</p>
    </div>

    <div class="footer">
      <p>&copy; 2026 <a href="https://www.nylas.com/" style="color: #0D6EFD;">Nylas</a></p>
      <p style="font-size: 12px; color: #999999; margin-top: 4px;">
        Booking reference: {{booking_info.event_id}}
      </p>
    </div>
  </div>
</body>

</html>


```

```html [schedulerAppTemplate-booking.pending]

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Booking request received</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;
      line-height: 1.6;
      color: #333333;
      margin: 0;
      padding: 0;
      background-color: #f9fbfe;
      font-size: 16px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      text-align: center;
      padding: 20px 0;
    }

    .content {
      background-color: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .detail-label {
      color: #666666;
      font-size: 14px;
      padding: 6px 16px 6px 0;
      vertical-align: top;
      white-space: nowrap;
    }

    .detail-value {
      padding: 6px 0;
      vertical-align: top;
    }

    .footer {
      text-align: center;
      padding: 20px 0;
      color: #666666;
      font-size: 14px;
    }

    @media only screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }

      .content {
        padding: 20px !important;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <img src="https://brand.nylas.com/assets/site_images/Nylas-Logo_Horizontal-Blue.png" alt="Nylas Logo"
        style="max-width: 150px;" />
    </div>

    <div class="content">
      <h1 style="margin-top: 0; color: #1A1A1A;">Your booking request was received</h1>

      {{#if recipient}}{{#if recipient.first_name}}<p>Hi {{recipient.first_name}},</p>{{else}}<p>Hi there,</p>{{/if}}{{else}}<p>Hi there,</p>{{/if}}

      <p>We've received your request for <strong>{{booking_info.title}}</strong>. It isn't confirmed yet — the organizer needs to approve it, and you'll get another email as soon as they do.</p>

      <hr style="border: 0; border-top: 1px solid #eeeeee; margin: 20px 0;" />

      <h2 style="color: #4D4D4D; font-weight: 500;">Meeting details</h2>

      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
        <tr><td class="detail-label">When</td><td class="detail-value">{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}</td></tr>
        <tr><td class="detail-label">Duration</td><td class="detail-value">{{booking_info.duration}} minutes</td></tr>
        {{#if booking_info.location}}<tr><td class="detail-label">Where</td><td class="detail-value"><a href="{{booking_info.location}}" style="color: #0D6EFD;">{{booking_info.location}}</a></td></tr>{{/if}}
        <tr><td class="detail-label">Who</td><td class="detail-value">{{#each booking_info.participants}}{{name}} &lt;{{email}}&gt;{{#unless @last}}<br />{{/unless}}{{/each}}</td></tr>
      </table>
      <div style="text-align: center; margin: 30px 0;"><a href="{{booking_info.participant_cancellation_url}}" style="background-color: #0D6EFD; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Withdraw request</a></div>
      <p style="font-size: 14px; color: #666666; text-align: center;">Nothing is on your calendar until the organizer confirms.</p>
    </div>

    <div class="footer">
      <p>&copy; 2026 <a href="https://www.nylas.com/" style="color: #0D6EFD;">Nylas</a></p>
      <p style="font-size: 12px; color: #999999; margin-top: 4px;">
        Booking reference: {{booking_info.event_id}}
      </p>
    </div>
  </div>
</body>

</html>


```

```html [schedulerAppTemplate-booking.reminder]

<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Your meeting starts soon</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        Helvetica, Arial, sans-serif;
      line-height: 1.6;
      color: #333333;
      margin: 0;
      padding: 0;
      background-color: #f9fbfe;
      font-size: 16px;
    }

    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .header {
      text-align: center;
      padding: 20px 0;
    }

    .content {
      background-color: #ffffff;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }

    .detail-label {
      color: #666666;
      font-size: 14px;
      padding: 6px 16px 6px 0;
      vertical-align: top;
      white-space: nowrap;
    }

    .detail-value {
      padding: 6px 0;
      vertical-align: top;
    }

    .footer {
      text-align: center;
      padding: 20px 0;
      color: #666666;
      font-size: 14px;
    }

    @media only screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }

      .content {
        padding: 20px !important;
      }
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="header">
      <img src="https://brand.nylas.com/assets/site_images/Nylas-Logo_Horizontal-Blue.png" alt="Nylas Logo"
        style="max-width: 150px;" />
    </div>

    <div class="content">
      <h1 style="margin-top: 0; color: #1A1A1A;">Your meeting starts soon</h1>

      {{#if recipient}}{{#if recipient.first_name}}<p>Hi {{recipient.first_name}},</p>{{else}}<p>Hi there,</p>{{/if}}{{else}}<p>Hi there,</p>{{/if}}

      <p>A reminder that <strong>{{booking_info.title}}</strong> is coming up.</p>

      <hr style="border: 0; border-top: 1px solid #eeeeee; margin: 20px 0;" />

      <h2 style="color: #4D4D4D; font-weight: 500;">Meeting details</h2>

      <table cellpadding="0" cellspacing="0" border="0" style="width: 100%;">
        <tr><td class="detail-label">When</td><td class="detail-value">{{#if recipient}}{{#if booking_info.additional_fields}}{{#if (lookup booking_info.additional_fields recipient.email)}}{{ formatDate booking_info.start_time (lookup booking_info.additional_fields recipient.email) "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}{{else}}{{#if booking_info.guest_timezone}}{{ formatDate booking_info.start_time booking_info.guest_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{else}}{{ formatDate booking_info.start_time booking_info.organizer_timezone "EEEE d LLLL yyyy, h:mm a ZZZZ" booking_info.guest_language }}{{/if}}{{/if}}</td></tr>
        <tr><td class="detail-label">Duration</td><td class="detail-value">{{booking_info.duration}} minutes</td></tr>
        {{#if booking_info.location}}<tr><td class="detail-label">Where</td><td class="detail-value"><a href="{{booking_info.location}}" style="color: #0D6EFD;">{{booking_info.location}}</a></td></tr>{{/if}}
        <tr><td class="detail-label">Who</td><td class="detail-value">{{#each booking_info.participants}}{{name}} &lt;{{email}}&gt;{{#unless @last}}<br />{{/unless}}{{/each}}</td></tr>
      </table>
      <div style="text-align: center; margin: 30px 0;"><a href="{{booking_info.location}}" style="background-color: #0D6EFD; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">Join the meeting</a></div>
      <p style="font-size: 14px; color: #666666; text-align: center;">Need to change it? <a href="{{booking_info.participant_rescheduling_url}}" style="color: #0D6EFD;">Reschedule</a> or <a href="{{booking_info.participant_cancellation_url}}" style="color: #0D6EFD;">cancel</a>.</p>
    </div>

    <div class="footer">
      <p>&copy; 2026 <a href="https://www.nylas.com/" style="color: #0D6EFD;">Nylas</a></p>
      <p style="font-size: 12px; color: #999999; margin-top: 4px;">
        Booking reference: {{booking_info.event_id}}
      </p>
    </div>
  </div>
</body>

</html>


```

Render each one with `POST /v3/templates/render` before enabling its workflow. A missing variable returns `400` and sends nothing, with no error on the booking request, so [Why isn't my workflow sending email?](/docs/cookbook/workflows/workflow-not-sending/) is worth reading before you go live.

## What's next

- [Customize Scheduler email for each user](/docs/cookbook/workflows/scheduler-email-per-user/) for per-customer branding and what it costs to run
- [Tell Scheduler attendees the meeting is recorded](/docs/cookbook/workflows/recording-notice-scheduler/) when bookings create a Notetaker session
- [Why isn't my workflow sending email?](/docs/cookbook/workflows/workflow-not-sending/) for the strict rendering rules
- [Customize the booking flow](/docs/cookbook/scheduler/customize-booking-flow/) for booking form fields and confirmation redirects
- [Scheduler notifications](/docs/reference/notifications/scheduler/) for the full payload of each booking trigger