# Smart Invites

Smart Invites are trackable calendar invite files that keep your application up to date with attendee status changes without needing a connection to their calendar. Your application can be notified when an attendee accepts the event or declines it from their calendar.

Healthcare appointments or interviews can then be rescheduled. A rental property viewing or restaurant booking can be auto cancelled and the slot made available to others.

Importantly the workflow decisions are yours but Cronofy gives you the real-time notification you need to trigger the appropriate process at the appropriate time.

If you're already sending invite files from your application then this is a really simple operation to swap out your existing ICS generation with Cronofy Smart Invites.

**Smart Invite flow**

Sequence diagram of a Smart Invite in six steps between your application, Cronofy and the invitee, ending with Cronofy sending your application a webhook when the invitee responds.

```mermaid
sequenceDiagram
autonumber

Your Application->>Cronofy: Create a Smart Invite
Cronofy->>Your Application: ICS file

Your Application->>Invitee: Email
Invitee->>Cronofy: Response

Cronofy->>Cronofy: Update status
Cronofy-->>Your Application: Webhook
```

1. Your application asks Cronofy to create a Smart Invite.
2. Cronofy returns an ICS file to your application.
3. Your application emails the invite to the invitee.
4. The invitee's response goes to Cronofy.
5. Cronofy updates the status of the invite.
6. Cronofy notifies your application of the change with a webhook.


> **WARNING:** **iCloud** calendars do not send responses when a recipient accepts or declines an invite.
This behavior also happens when non-Cronofy invites are sent. iCloud users cannot share attending status with non-iCloud calendars until Apple addresses the underlying issue.
This means that Smart Invites sent to iCloud email addresses will not receive status updates and callback.

Please note that this restriction is because of *iCloud* rather than Apple devices - a Smart Invite accepted on an iPhone into a Google Calendar will still work.

> **WARNING:** Calendar providers do not send responses when a recipient deletes an event on their calendar.
As there is no response to capture from deleting an event, attending status will not be updated and no callback will be sent.

## Creating your first Smart Invite
A single API call is all that's needed to generate the invite you can allow the user to download or send via email.

```http
POST /v1/smart_invites HTTP/1.1
Host: {data_center_url}
Authorization: Bearer {API_KEY}
Content-Type: application/json; charset=utf-8

{
  "recipient": {
    "email": "cronofy@example.com"
  },
  "smart_invite_id": "your-unique-identifier-for-invite",
  "event": {
    "summary": "Board meeting",
    "description": "Discuss plans for the next quarter.",
    "start": "2026-11-13T09:30:00Z",
    "end": "2026-11-13T10:30:00Z",
    "tzid": "Europe/London",
    "location": {
      "description": "Board room"
    }
  },
  "callback_url": "https://example.com/smart_invite/notifications"
}
```

The key attributes from the above sample request are as follows,

##### `API_KEY`

This is the `client_secret` for your Application in the [Cronofy Developer Dashboard](https://app.cronofy.com/jump/developer).

##### `recipient`

This contains the email address of the attendee.

##### `smart_invite_id`

Your unique identifier for the Smart Invite.

##### `event`

This contains all the fields for the event.

##### `callback_url`

The url for Cronofy to 'POST' updates to whenever the attendee status changes.

Further details on these parameters can be found [here](https://docs.cronofy.com/api-reference/calendar-control/smart-invites/create-single-smart-invite/index.md).

```json
{
  "event": {...},
  "attachments": { "icalendar": "BEGIN:VCALENDAR\nVERSION:2.0..." }
}
```

## Sending the Smart Invite
**Cronofy does not send the email.**

The majority of email clients will automatically add calendar invites to a user's calendar if you follow these instructions. This will also mean that, where supported, the user will be presented with the Accept/Decline helpers in their email client.

The two key things to do are:

- Format the ICS correctly.

- Attach the ICS to the email in the correct ways.

Of course, Smart invites created through the [Cronofy Smart Invite API Endpoint](https://docs.cronofy.com/api-reference/calendar-control/smart-invites/create-single-smart-invite/index.md) will be in the correct format. When it comes to attaching the ICS file to the email that's something your app will need to handle.

The sample code below shows how the attachments should be added. In short you need to attach the file twice. Once inline with 7bit encoding, the other as a standard attachment but with Base64 encoding.

For more detailed best practices, we recommend following the [iMIP Best Practices](https://devguide.calconnect.org/iMIP/iMIPBest-Practices/) for sending invites. This will guarantee the widest support.


```ruby
# Using Rails

class SmartInviteMailer < ActionMailer::Base
  def invite(smart_invite)
    event_ics = smart_invite.attachments.icalendar

    method = 'REQUEST' # method=CANCEL in the case of cancellations

    attachments.inline["invite.ics"] = {
      content_type: "text/calendar; charset=UTF-8; method=#{method}",
      encoding: '7bit',
      content: event_ics,
    }

    attachments["invite.ics"] = {
      content_type: "application/ics; charset=UTF-8; method=#{method}",
      encoding: 'base64',
      content: Base64.encode64(event_ics),
    }

    invite_mail = mail(
      to: smart_invite.recipient.email,
      subject: "Smart Invite Example",
      body: "Here is your invite."
    )

    # In Rails >= 6, we need to change ActionMailers default inline attachment content-type
    # to match the iMIP best practices for sending calendar invites, so that Outlook can show
    # the Accept/Tentative/Decline buttons in line.
    invite_mail
      .parts
      .select { |part| contains_calendar_subpart?(part) }
      .each { |part| replace_multipart_type(part) }
  end

  private def contains_calendar_subpart?(part)
    part.parts.any? { |subpart| subpart.content_type.start_with? "text/calendar" }
  end

  private def replace_multipart_type(part)
    new_content_type = part.content_type.sub(%r{multipart/[\w]+}, "multipart/alternative")
    part.content_type = new_content_type
    part
  end
end
```


```php
// Using the https://github.com/PHPMailer/PHPMailer script

require '../vendor/autoload.php';

$mail = new PHPMailer();

$mail->setFrom('application@example.com');
$mail->addAddress($invite->recipient->email);
$mail->Subject = 'Smart Invite Example';
$mail->Body = 'Here is your invite';

$ics = $invite->attachments->icalendar;

$method = 'REQUEST' // method=CANCEL in the case of cancellations

$mail->addAttachment($ics, 'invite.ics', '7bit', "text/calendar; charset=UTF-8; method=$method", 'inline');
$mail->addAttachment(base64_encode($ics), 'invite.ics', 'base64', "application/ics; charset=UTF-8; method=$method", 'attachment');

$mail->send();
```


```javascript
// Using the https://nodemailer.com/about/ library

const nodemailer = require('../lib/nodemailer');

// TODO configure transport as required
let transporter = nodemailer.createTransport({});

let ics = invite.attachments.icalendar;

let method = 'REQUEST'; // method=CANCEL in the case of cancellations

let message = {
    to: invite.recipient.email,
    subject: 'Smart Invite Example',
    text: 'Here is your invite',
    attachments: [
        {
            filename: 'invite.ics',
            content: ics,
            contentType: `text/calendar; charset=UTF-8; method=${method}`,
            contentDisposition: 'inline'
        },
        {
            filename: 'invite.ics',
            content: Buffer.from(ics, 'base64'),
            contentType: `application/ics; charset=UTF-8; method=${method}`,
            encoding: 'base64'
        },
    ]
};

transporter.sendMail(message, (error, info) => {
    transporter.close();
});
```


```csharp
var message = new MailMessage("application@example.com", invite.Recipient.Email);
message.Subject = "Smart Invite Example";
message.Body = "Here is your invite";

var ics = invite.Attachments.ICalendar;

var method = "REQUEST"; // method=CANCEL in the case of cancellations

var inlineAttachment = new Attachment(
    new MemoryStream(Encoding.UTF8.GetBytes(ics)),
    "invite.ics",
    $"text/calendar; charset=UTF-8; method={method}"
);
inlineAttachment.ContentDisposition.Inline = true;

var attachment = new Attachment(
    new MemoryStream(Encoding.UTF8.GetBytes(ics)),
    "invite.ics",
    $"application/ics; charset=UTF-8; method={method}"
);

message.Attachments.Add(inlineAttachment);
message.Attachments.Add(attachment);
```



## Tracking Attendee Status
You can request the current status of a Smart Invite by querying the `/v1/smart_invites` API endpoint.

```http
GET /v1/smart_invites?recipient_email=cronofy@example.com&smart_invite_id=your-unique-identifier-for-invite HTTP/1.1
Host: {data_center_url}
Authorization: Bearer {API_KEY}
```

You'll receive back the entire information about that invitation including the following attributes.

```json
{
  "recipient": {
    "email": "cronofy@example.com",
    "status": "pending"
  },
  "replies": [
    {
      "email": "person1@example.com",
      "status": "accepted"
    },
    {
      "email": "person2@example.com",
      "status": "declined"
    }
  ],
}
```

##### `recipient`

This is the same as the submission with the addition of a status attribute indicating whether the recipient has accepted or not.

##### `replies`

Is a list of all replies to the invite. This will usually be the same as the recipient but it's presented as a separate attribute because it is possible for other people to reply to the calendar invite. This can be when email aliases are used or when the recipient is a team mailbox that is shared by multiple people.

You can then see at any time, who's accepted, who's declined and make sure your application and thus your user is fully informed.

## Status Update Callbacks
The last concept to cover is the callback. Whenever a reply is received, Cronofy will generate a webhook to the `callback_url` you specified when creating the event. The body will be similar to this:

```json
{
  "notification": {
    "type": "smart_invite"
  },
  "smart_invite": {
    "recipient": {
      "email": "cronofy@example.com",
      "status": "accepted"
    },
    "smart_invite_id": "your-unique-identifier-for-invite",
    "callback_url": "https://example.com/..."
  }
}
```

## Custom organizer email
Smart Invites are able to use a custom organizer email rather than using Cronofy's
default.

Works for both single- and multiple-recipient Smart Invites.

### Purpose
As well as enabling stronger branding of your invites, some calendar services
and clients can refuse to process invites where the sender of the email does not
match the organizer embedded within the event. Being able to set the organizer's
email address avoids this problem as it allows the two to be the same.

### Email forwarding
In order to function, emails sent to your custom organizer address **must** be
forwarded to Cronofy for processing. This ensures that the invite status is received by Cronofy as per the below flow:

**Forwarding responses from a custom organizer email**

Sequence diagram of a Smart Invite with a custom organizer in six steps, where the organizer email account forwards the user's response to Cronofy, which notifies your application with a webhook.

```mermaid
sequenceDiagram
autonumber

participant Your Application
participant Cronofy
participant Organizer email account
participant User calendar

Your Application->>Cronofy: Create a Smart#nbsp;Invite with a custom organizer
Cronofy->>Your Application: ICS file
Your Application->>User calendar: Send the ICS file
User calendar->>Organizer email account: Accept or reject
Organizer email account->>Cronofy: Forward the response
Cronofy-->>Your Application: Webhook
```

1. Your application asks Cronofy to create a Smart Invite with a custom organizer email.
2. Cronofy returns the ICS file to your application.
3. Your application sends the ICS file to the user, who opens it in their calendar.
4. The user accepts or rejects the invite in their calendar, which sends the response to the organizer's email account.
5. The organizer's email account forwards the response to Cronofy.
6. Cronofy notifies your application of the response with a webhook.


#### Forwarding addresses
The forwarding address used varies by data centre as follows:

<table>
  <thead>
      <tr>
          <th> </th>
          <th>Forwarding address</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>AU 🇦🇺</td>
          <td>organizer@invite-au.cronofy.com</td>
      </tr>
      <tr>
          <td>CA 🇨🇦</td>
          <td>organizer@invite-ca.cronofy.com</td>
      </tr>
      <tr>
          <td>DE 🇩🇪</td>
          <td>organizer@invite-de.cronofy.com</td>
      </tr>
      <tr>
          <td>SG 🇸🇬</td>
          <td>organizer@invite-sg.cronofy.com</td>
      </tr>
      <tr>
          <td>UK 🇬🇧</td>
          <td>organizer@invite-uk.cronofy.com</td>
      </tr>
      <tr>
          <td>US 🇺🇸</td>
          <td>organizer@invite.cronofy.com</td>
      </tr>
  </tbody>
</table>
Without forwarding in place, responses such as acceptance and declines, **will
not reach Cronofy and so not be processed**.

It is recommended that this address be specific to invites rather than a generic
"no reply" address you may already have set up. For example we commonly see
people using a generic email address like `organizer@example.com`.

- [Configuring invite forwarding for Google Workplace](https://docs.cronofy.com/developers/calendar-and-availability/calendar-events/smart-invites/google-workplace/index.md)

### Configuring the organizer email
Once the forwarding is set up, all you need to do is specify the organizer email
when creating the Smart Invite, as [documented here](https://docs.cronofy.com/api-reference/calendar-control/smart-invites/create-single-smart-invite/index.md).

This is a quick introduction to Smart Invites. If you have any further questions please send us an email at [support@cronofy.com](mailto:support@cronofy.com) or go to [this](https://docs.cronofy.com/api-reference/calendar-control/smart-invites/create-single-smart-invite/index.md) page for a more detailed look at creating and updating smart invites.


---
[Read in HTML](https://docs.cronofy.com/developers/calendar-and-availability/calendar-events/smart-invites/)

## In this section

