Smart Invites
Read as Markdown Required plan: EmergingSmart 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.
Step by step
- Your application asks Cronofy to create a Smart Invite.
- Cronofy returns an ICS file to your application.
- Your application emails the invite to the invitee.
- The invitee’s response goes to Cronofy.
- Cronofy updates the status of the invite.
- Cronofy notifies your application of the change with a webhook.
Diagram source
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: WebhookCreating 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.
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.
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.
{
"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 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 for sending invites. This will guarantee the widest support.
# 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// 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();// 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();
});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.
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.
{
"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:
{
"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:
Step by step
- Your application asks Cronofy to create a Smart Invite with a custom organizer email.
- Cronofy returns the ICS file to your application.
- Your application sends the ICS file to the user, who opens it in their calendar.
- The user accepts or rejects the invite in their calendar, which sends the response to the organizer’s email account.
- The organizer’s email account forwards the response to Cronofy.
- Cronofy notifies your application of the response with a webhook.
Diagram source
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: WebhookForwarding addresses #
The forwarding address used varies by data centre as follows:
| Forwarding address | |
|---|---|
| AU 🇦🇺 | organizer@invite-au.cronofy.com |
| CA 🇨🇦 | organizer@invite-ca.cronofy.com |
| DE 🇩🇪 | organizer@invite-de.cronofy.com |
| SG 🇸🇬 | organizer@invite-sg.cronofy.com |
| UK 🇬🇧 | organizer@invite-uk.cronofy.com |
| US 🇺🇸 | organizer@invite.cronofy.com |
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 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.
This is a quick introduction to Smart Invites. If you have any further questions please send us an email at support@cronofy.com or go to this page for a more detailed look at creating and updating smart invites.