URL: /code/integrations/outlook · Id: `page:/code/integrations/outlook`

# Outlook

> Your agents send from your Outlook address, read every reply, and book the call on your Outlook calendar.

Your agents send from your Outlook address, read every reply, and book the call on your Outlook calendar.

```text title="Run it · Ask"
Book a 30-minute call with Rosa at Northgate Rentals in my next free weekday slot, and show me the invite.
```

```ts title="Run it · SDK"
import { $ } from 'startup-builder'

const result = await $.try.Meeting.book({ contact: 'contacts/rosa-northgate', at: 'next free 30 minutes, weekdays 10:00 to 16:00 America/Chicago' })
```

```json title="Run it · Response"
{
  "$type": "Meeting",
  "mode": "try",
  "stored": false,
  "contact": "rosa@northgate-rentals.com",
  "at": "2026-10-29T15:30:00Z",
  "calendar": "outlook",
  "invite": {
    "subject": "Leaseline and the Northgate rent spreadsheet, 30 minutes",
    "from": "dana@leaseline.app"
  },
  "agenda": "How Northgate tracks rent and renewals today"
}
```

- **Connect:** Sign in once, 4 grants
- **Runs through:** [Your account](/code/integrations#three-ways)
- **First run:** Enroll 25 checked people in your first Sequence, free on your account
- **Sites:** [Outlook](/venues#outlook)

## Connect once
1. Call `Integration.connect` with `system: 'mailboxes'` and `venue: 'outlook'`, then open the `connectUrl` it returns and sign in as the Microsoft work or personal account you send from.
2. Approve the four grants Microsoft lists. A work account whose admin restricts apps asks the admin once; the `connectUrl` waits an hour for it.
3. Authenticate the sending Domain once with `Domain.authenticate`, which writes SPF, DKIM and DMARC and checks them before the first send.

| Grant | What it unlocks | Scope |
| --- | --- | --- |
| Send as you | Each Sequence step, reply and broadcast leaves from your own address | `Mail.Send` |
| Read replies | Every reply lands on its thread and its lead; the platform reads no thread your agents did not start | `Mail.Read` |
| Your calendar | Free and busy times, and the Meetings your agents book, on your Outlook calendar | `Calendars.ReadWrite` |
| Stay connected | Your agents keep working without you signing in each day | `offline_access` |

| To | Do this |
| --- | --- |
| Pause | `Integration.pause` stops every call through Microsoft at once and keeps the token; `Integration.resume` picks up from the same cursor. |
| Reconnect | `Integration.reconnect` returns a fresh `connectUrl` that lasts one hour, and keeps the Integration's id and cursor, so nothing imports twice. |
| Disconnect | `Integration.revoke` revokes the token with Microsoft; every record it brought in stays in your records. |

## What your agents do
| Ask | Verb | Runs through | Price |
| --- | --- | --- | --- |
| Send each step of my Sequence from my Outlook address, and stop on any reply. | [`Contact.enroll`](/code/apps/sequences/enroll) | Your account | Free |
| Hold this reply until 9:00 in their time zone, then send it. | [`Message.schedule`](/code/apps/mailboxes/schedule) | Your account | Free |
| Send the launch note to my waitlist. | [`Message.broadcast`](/code/apps/mailboxes/broadcast) | Your account | Free |
| Book the call this reply asks for, on my Outlook calendar. | [`Meeting.book`](/code/apps/scheduling/book) | Your account | Free |
| Answer this reply in the same thread. | [`Conversation.answer`](https://startupbuilder.dev/business/nouns/conversation/answer) | Your account | Free |
| Stop every send to anyone who asks. | [`Contact.unsubscribe`](https://startupbuilder.dev/business/nouns/contact/unsubscribe) | Your account | Free |

Calls on your own account are free.

## What it holds
| Noun | The account’s object | When | Which side leads |
| --- | --- | --- | --- |
| [Message](https://startupbuilder.dev/business/nouns/message) | `message` | Your agent sends a step, a reply or a broadcast | Your records |
| [Message](https://startupbuilder.dev/business/nouns/message) | `message` | A reply arrives in the inbox | The account |
| [Thread](https://startupbuilder.dev/business/nouns/thread) | `conversationId` | The first send opens it; every reply joins it | The account |
| [Meeting](https://startupbuilder.dev/business/nouns/meeting) | `event` | Your agent books a call | Your records |

## Events and webhooks
| Direction | Event |
| --- | --- |
| Emits | `Message.created`, `Contact.enrolled`, `Message.broadcasted`, `Meeting.booked`, `Prospect.engaged`, `Contact.unsubscribed` |
| Hears `subscription: me/messages` | Becomes `Message.created` |
| Hears `subscription: me/events` | Becomes `Meeting.updated` |

Any Event can wake a Workflow, and a Watch delivers it to your endpoint, signed ([Events and webhooks](/code/events)).

## Limits
| What | Limit | Call |
| --- | --- | --- |
| Recipients from one mailbox | 10,000 in a rolling 24 hours on Exchange Online; past it the mailbox sends nothing until the oldest sends age out, so the call returns `quota-reached` with the time | [`Message.broadcast`](/code/apps/mailboxes/broadcast) |
| Send rate | 30 messages a minute; the platform paces a broadcast under it, so Microsoft never throttles a send | [`Message.broadcast`](/code/apps/mailboxes/broadcast) |
| Cold sends | 30 a day per inbox after 14 days of warm-up, held by your standing approval; a Sequence spreads the rest over the next days | [`Contact.enroll`](/code/apps/sequences/enroll) |
| Bookings | Only inside your bookable hours and never over a busy block on any connected calendar | [`Meeting.book`](/code/apps/scheduling/book) |

## Field map
| Our field | Outlook’s field | Notes | Calls |
| --- | --- | --- | --- |
| `Message.to` | `message.toRecipients` | None. | [`Message.schedule`](/code/apps/mailboxes/schedule), [`Message.broadcast`](/code/apps/mailboxes/broadcast), [`Contact.enroll`](/code/apps/sequences/enroll) |
| `Message.subject` | `message.subject` | None. | [`Message.schedule`](/code/apps/mailboxes/schedule), [`Message.broadcast`](/code/apps/mailboxes/broadcast), [`Contact.enroll`](/code/apps/sequences/enroll) |
| `Message.body` | `message.body` | contentType html or text | [`Message.schedule`](/code/apps/mailboxes/schedule), [`Message.broadcast`](/code/apps/mailboxes/broadcast), [`Contact.enroll`](/code/apps/sequences/enroll) |
| `Message.purpose` | `message.internetMessageHeaders` | A commercial purpose adds the one-click unsubscribe headers | [`Message.broadcast`](/code/apps/mailboxes/broadcast), [`Contact.enroll`](/code/apps/sequences/enroll) |
| `Meeting.at` | `event.start and event.end` | Each with its timeZone | [`Meeting.book`](/code/apps/scheduling/book) |
| `Meeting.contact` | `event.attendees[].emailAddress` | None. | [`Meeting.book`](/code/apps/scheduling/book) |
| `Meeting.agenda` | `event.body` | None. | [`Meeting.book`](/code/apps/scheduling/book) |

## What try does here
Renders the exact email or invite and returns it with the time it would go; nothing reaches Outlook and no draft or event is saved.

## How long a connection lasts
A connection lasts 90 days from its last use: Microsoft replaces the refresh token on every use, and your agents use it daily.

The platform asks you to reconnect 7 days before it runs out; until you do, a call that needs it refuses with [`needs-reauth`](/code/refusals#needs-reauth).

## Plays and strategies
| Kind | Where |
| --- | --- |
| Plays | [Cold email](/plays/cold-email), [Buying committee](/plays/buying-committee), [lead nurture](/plays/lead-nurture), [customer referrals](/plays/customer-referrals), [Owned newsletter](/plays/owned-newsletter) |
| Strategies | [Hands-on](/strategy/hands-on) |

## Used by
- **Agent tasks:** [Launch day](/capabilities/earn-first-links/launch-day) · [Link pitches](/capabilities/earn-first-links/link-pitches) · [Answer every inbound](/capabilities/convert-visitors/answer-every-inbound) · [Personal first touch](/capabilities/reach-out/personal-first-touch)
- **Services:** [Booked first calls](/capabilities/reach-out/booked-first-calls) · [Demand generation](/capabilities/find-customers/demand-generation)

## Reference

| Call | Path | Price |
| --- | --- | --- |
| [`Contact.enroll`](/code/apps/sequences/enroll) | `POST /contacts/enroll` | Free |
| [`Message.schedule`](/code/apps/mailboxes/schedule) | `POST /messages/schedule` | Free |
| [`Message.broadcast`](/code/apps/mailboxes/broadcast) | `POST /messages/broadcast` | Free |
| [`Meeting.book`](/code/apps/scheduling/book) | `POST /meetings/book` | Free |
| [`Conversation.answer`](https://startupbuilder.dev/business/nouns/conversation/answer) | `POST /conversations/answer` | Free |
| [`Contact.unsubscribe`](https://startupbuilder.dev/business/nouns/contact/unsubscribe) | `POST /contacts/unsubscribe` | Free |