MS vs MailKite logo
Alternative to Microsoft Graph (Outlook)

An agent inbox with no app registration, no admin consent, no subscription to renew.

Microsoft Graph gives an agent a real Outlook mailbox, at the cost of an Entra app registration, admin-consented (tenant-wide) mail permissions, and a change-notification subscription that expires every few days. MailKite gives the agent its own scoped address on a domain you control and pushes parsed, authenticated JSON to a receive→reply loop — nothing to register, renew, or keep alive.

A fair take on Microsoft Graph (Outlook)

Graph is the right tool — sometimes the only tool — when the agent must operate inside a real Microsoft 365 tenant: one consistent API across mail, calendar, contacts, Teams, OneDrive, and SharePoint, carrying the mailbox's real history, identity, and compliance. Nothing on the market matches that reach into M365.

How it works

Microsoft Graph (Outlook) vs MailKite, in one diagram

MSMicrosoft Graph (Outlook) email in M365 mailboxlicensed acct subscriptionexpires in days notify → GET msghandshake + app token your agent …plus the Entra ID app registration, admin-consented Graph permissions (tenant-wide by default), and the renewal cron that re-subscribes before each subscription lapses MailKite email in MX edgeparse + auth JSON webhooksigned, retried, replayable your agent no app registration, no admin consent, no subscription to renew — the webhook just arrives
Why teams switch

What MailKite does differently

No directory identity to stand up

Skip the Entra ID app registration, the client secret or certificate (which itself expires), and the admin-consent chase. You DNS-verify a domain and point a webhook at it — the address is the whole setup.

No tenant-wide grant to scope back

Graph application permissions like Mail.Read read every mailbox in the tenant by default, and Mail.Send sends as any user — so you add RBAC for Applications and remember an unscoped grant isn't narrowed by it. On MailKite the address is the scope; there's nothing wider to confine.

Durable webhook, nothing to renew

Graph mail subscriptions cap under 7 days (under 1 day if you include the body); a dropped renewal cron silently stops inbound. MailKite's webhook is durable — no expirationDateTime, no PATCH-on-a-cron, no validationToken handshake.

Parsed, authenticated JSON — one hop

A Graph change notification is a pointer: you GET the message with an app token to read it, and nothing tells you if SPF/DKIM/DMARC passed. MailKite POSTs the full parsed message with an auth block already resolved — no second round-trip, no re-deriving sender trust.

Side by side

MailKite vs Microsoft Graph (Outlook)

MailKite Microsoft Graph (Outlook)
Give the agent an inbox Scoped address on a domain you control Licensed M365 mailbox + Entra app
Setup to start DNS-verify, one webhook URL App registration + admin consent (tenant-wide)
Inbound delivery One parsed JSON webhook Change-notification ping → you GET the message
Push subscription Durable — nothing to renew Expires (≤7d, ≤1d with body); renew on a cron
Scope to one mailbox The address is the scope RBAC for Applications / access policy
Sender auth for the agent auth block in every payload You derive SPF/DKIM/DMARC yourself
Reach beyond mail (calendar, Teams, files) Email only One API across all of M365
Cost floor Free: 3,000 msg/mo, no per-domain fee Per-user license (~$4–6/mo) + your infra

Competitor capabilities change — we re-audit these tables regularly. Spot something out of date? Tell us and we'll fix it.

Show the payload

What actually hits your webhook

Graph hands you a pointer you must authenticate, GET, and re-subscribe to keep alive; MailKite POSTs the parsed message with the auth verdict already resolved.

Graph app-only inbox (token → subscribe → handshake → GET)
http
// Needs an Entra app with admin-consented application Mail.Read,
// ideally RBAC-scoped to one mailbox. A notification is a pointer,
// not the message — you GET it with an app token.
await fetch("https://graph.microsoft.com/v1.0/subscriptions", {
method: "POST",
headers: { authorization: `Bearer ${appToken}`, "content-type": "application/json" },
body: JSON.stringify({
changeType: "created",
notificationUrl: NOTIFY_URL,
resource: `/users/${MAILBOX}/mailFolders('inbox')/messages`,
expirationDateTime: new Date(Date.now() + 6 * 864e5).toISOString(), // lapses — re-PATCH it
}),
});

// On your notify endpoint:
// 1. validation handshake — echo ?validationToken back, text/plain, 200, within 10s
// 2. a change notification arrives → GET the message with a fresh app token
const { value } = JSON.parse(body);
const msg = await fetch(`https://graph.microsoft.com/v1.0/${value[0].resource}`, {
headers: { authorization: `Bearer ${await token()}` },
}).then((r) => r.json());
// msg.body.content is HTML; nothing here tells you if SPF/DKIM/DMARC passed.
MailKite
json
POST /your-webhook   Content-Type: application/json
x-mailkite-signature: t=…,v1=… (HMAC-SHA256 — verify locally)

{
"id": "msg_2Hk9…",
"type": "email.received",
"from": { "address": "ada@example.com" },
"to": [{ "address": "support@myapp.ai" }],
"subject": "Re: invoice #1042",
"text": "Looks good — approved!",
"html": "<p>Looks good — approved!</p>",
"threadId": "<a1b2c3@mail.example.com>",
"auth": { "spf": "pass", "dkim": "pass", "dmarc": "pass", "spam": "ham" },
"attachments": [
{ "filename": "po.pdf", "contentType": "application/pdf",
"size": 18213, "url": "https://api.mailkite.dev/att/2Hk9…/0?sig=…" }
]
}
The price advantage

Unlimited domains. One quota. Free to start.

MailKite

  • Free: 3,000 emails/mo (in + out)
  • Unlimited domains on every plan
  • Pro $20/mo → 50,000, graceful overage

Microsoft Graph (Outlook)

  • Per-user M365 license (~$4–6/mo) for the mailbox
  • Plus your own infra: notify endpoint + renewal cron
  • Throttled at 10,000 requests / 10 min per app per mailbox

Graph's mailbox needs a licensed account and you host the subscription lifecycle yourself; MailKite's agent address lives on a domain you already control, with no per-domain fee and one combined quota.

See full MailKite pricing →

Switch in an afternoon

Moving from Microsoft Graph (Outlook)

  1. 1

    Point a domain at MailKite

    DNS-verify a domain (MX to receive, SPF + DKIM to send) and pick an address like agent@yourco.dev. No Entra app, no admin to chase for consent.

  2. 2

    Swap the subscription loop for one webhook

    Delete the token cache, the /subscriptions POST, the validationToken handshake, and the renewal cron. Point one webhook URL at your endpoint — inbound arrives as email.received, already parsed.

  3. 3

    Read the auth block and reply

    Verify x-mailkite-signature with the SDK's verifyWebhook, weight the sender by event.auth, then reply through the same send API — or let a route with action:'agent' run the receive→reply loop for you.

Questions

Can an AI agent read an Outlook mailbox with Microsoft Graph?

Yes. For an autonomous, no-user agent you register an app in Entra ID, get admin consent for application mail permissions (Mail.Read, Mail.Send), then subscribe to change notifications and GET each message. It works well — especially when the agent lives inside a real M365 tenant. It's just more setup than pointing a domain at a webhook, which is the MailKite path.

Do Microsoft Graph mail subscriptions really expire?

Yes, and it's the part that bites. A messages subscription caps at 10,080 minutes (just under 7 days), or 1,440 minutes (under 1 day) if you include the body in the notification. You renew it with a PATCH before it lapses; if the cron dies, inbound quietly stops. MailKite's webhook is durable, so there's nothing to renew.

When should I stay on Graph instead of MailKite?

When the agent must operate as someone inside a real M365 tenant and touch the rest of it — calendar, contacts, Teams, OneDrive, SharePoint — under that org's identity, compliance, and retention. Graph is one API across all of M365. Pick MailKite when the agent just needs its own scoped inbox with no directory app, consent, or subscription lifecycle.

Go deeper

The Microsoft Graph (Outlook) alternative for AI agents →

The long-form take on our blog — receipts, runnable code, and where we won't overclaim.

Try MailKite free — keep Microsoft Graph (Outlook) running until you're ready.

Point a domain, drop in a webhook URL, receive your first email. Unlimited domains, no credit card.