Instruction
Difficulty level:
Implementing the Outlook integration: test and production checklist
This article is the practical implementation guide for the Outlook integration, with a checklist for both a test environment and production. The same app registration, permissions and infrastructure apply to both; in test you want a throw-away tenant in which you can freely create, change and delete calendar items on user and room mailboxes. The numbered steps below describe the order; then use the per-environment checklists.
Infrastructure requirements (push + polling)
The integration uses both Graph change-notification subscriptions (push) and a cron polling fallback. For a realistic test, both must work.
- Public webhook endpoint: Graph subscriptions post to
{base_url}/api/rest/integrationcalendarwebhook/outlook. This endpoint must be publicly reachable from Microsoft and echo thevalidationTokenhandshake (anonymous/public by design). On a local dev box this means a tunnel (ngrok / Cloudflare tunnel) or a publicly reachable test host; without validation Graph cannot create a subscription. - Subscription lifecycle: one subscription per synced calendar (delegated: one on
me; application: one per room). Subscriptions expire after 3 days and are renewed by cron within 2 days of expiry. - Cron + worker: the
ExecuteIntegrationscron must run for renewal and the polling fallback (> 30 min no sync). With queued processing a worker (RabbitMQ) must run for theintegration_calendar_inboundandintegration_calendar_renew_webhookjobs. Restart workers + clear OPcache after deploying worker/config changes.
Checklist — test environment
- ☐ Single-tenant Entra ID app registration created in the test tenant.
- ☐ Client secret generated (no certificate).
- ☐ Redirect URI set to
{base_url}/integrations/redirect/{int_id}. - ☐ Tenant ID, Client ID and Client secret noted.
- ☐ Delegated
Calendars.ReadWriteadded (for mode A). - ☐ Application
Calendars.ReadWriteadded + admin consent (for mode B). - ☐ ApplicationAccessPolicy restricts the app to a security group with room mailboxes.
- ☐ Dedicated M365 service account for delegated auth (not a personal account).
- ☐ User mailbox available (mode A) / room mailboxes + UPNs available (mode B).
- ☐ Public webhook URL reachable by Graph and echoing
validationToken. - ☐
ExecuteIntegrationscron running (renewal + polling fallback). - ☐ Worker (RabbitMQ) running if queued processing is used.
- ☐ Auth screen filled + Step 1 consent + Step 2 connect done.
- ☐ Config screen filled, mode chosen, object/rooms mapped, integration active.
- ☐ End-to-end tested: item created in Outlook → booking in i-Reserve; and (delegated) booking status change → item in Outlook.
Checklist — production environment
- ☐ A separate (or deliberately the same) app registration in the customer's production tenant; production secret managed separately.
- ☐ Permissions and (for app-only) admin consent granted in the production tenant.
- ☐ ApplicationAccessPolicy set in production too (no tenant-wide access).
- ☐ Production redirect URI registered against the production base url.
- ☐ Webhook endpoint publicly reachable in production (no tunnel; real host/SSL).
- ☐
ExecuteIntegrationscron and worker(s) running in production; OPcache cleared after deploy. - ☐ Real room mailboxes ↔ correct i-Reserve objects mapped (no test objects).
- ☐ “E-mail on problems” set to a monitored address.
- ☐ First live sync verified + webhook status checked on the diagnostics screen.
- ☐ Rollback known: setting the integration inactive stops sync without losing data.
In the right tenant create a single-tenant app registration, generate a client secret and note Tenant ID, Client ID and secret. Set the redirect URI.
Add the Graph permission Calendars.ReadWrite for the chosen mode (delegated and/or application). For application mode grant admin consent and restrict the app with an ApplicationAccessPolicy.
Delegated: provide a dedicated licensed service account. Application: create the room mailboxes, note the UPNs and put them in the security group.
Ensure the webhook endpoint is publicly reachable and echoes the validationToken, and that the ExecuteIntegrations cron and (if used) the RabbitMQ worker are running.
In i-Reserve fill the authentication screen (tenant/client/secret/return url), run consent + connect, choose the mode and map object(s)/rooms. Set the inbound behaviour fields.
Set the integration active, activate the webhook(s) and verify on the diagnostics screen that the subscription(s) were created. Test inbound end-to-end (and outbound for delegated) and complete the per-environment checklist.





