1. Migrate
  2. Exchange Web Services
MigrateFrom EWS

Replace your EWS integration before April 2027.

Exchange Online started switching EWS off on October 1, 2026. Workwae connects Microsoft 365 mailboxes through Microsoft Graph and gives your code one API for mail, calendars and contacts, so there is no EWS client left to port.

  • Graph under the hood
  • GCC High and DoD
  • Webhooks instead of streams
unread.tsunread.py
// Before: FindItem over EWS, SOAP, a stored mailbox login
// After: one call, whichever provider the mailbox is on
const { items } = await workwae.messages.list({
  accountId,
  unread: true,
});
# Before: FindItem over EWS, SOAP, a stored mailbox login
# After: one call, whichever provider the mailbox is on
page = workwae.messages.list(
    account_id=account_id,
    unread=True,
)
Why now

The dates that decide your plan.

As of October 30, 2026, from Microsoft’s deprecation page and Exchange Team blog.

October 1, 2026

Phased disablement starts. Tenants that never set EWSEnabled are switched to False, and EWS calls get a 403.

An admin can re-enable it

Until April 2027, a tenant admin can turn EWS back on, with an app ID allow list. Your customers decide that, not you.

April 1, 2027

EWS is disabled for good in Exchange Online, with no exceptions past that date.

On-premises Exchange stays

Exchange Server keeps EWS. Workwae does not speak EWS, so on-premises servers connect over IMAP and SMTP.

The full timeline, the tenant controls and the Graph mapping are in Exchange Web Services is being retired.

How it works

Rewrite the calls, reconnect the mailboxes.

There is no EWS import. Workwae has no EWS connector, so the move is a code change plus one sign-in or admin consent per mailbox.

  1. Inventory what you call

    List the EWS operations your code uses and whether it runs as the user or impersonates mailboxes. Most apps use a handful.

  2. Pick the connection

    Delegated sign-in for each user, or an organization connection that an administrator consents to for many mailboxes.

  3. Connect mailboxes

    Send users through hosted connect, keyed to your own record with externalRef.

  4. Swap the calls

    Replace each EWS operation with its Workwae call, from the table below.

  5. Replace subscriptions

    Drop the streaming, pull or push subscription and add a Workwae webhook endpoint.

  6. Switch and retire

    Run both side by side per mailbox, then remove your app from the tenant’s EWS allow list.

Consent

Graph permissions are a new consent.

An EWS app holds EWS.AccessAsUser.All or full_access_as_app. Graph asks for separate permissions, so plan for users or an administrator to consent again.

Delegated, per user

Hosted connect asks for Mail.ReadWrite and Mail.Send, plus Calendars.ReadWrite and Contacts.ReadWrite only when you turn those on.

App-only, per directory

An organization connection uses your Entra app with Graph application permissions, consented by an administrator. It replaces full_access_as_app and impersonation.

Your app or ours

Use your own Entra app so the consent screen names your product, or the platform app. GCC High and DoD need an app registered in that cloud.

Shared mailboxes

A delegated grant with the .Shared permissions opens the shared mailboxes the user can reach.

connect.tsconnect.py
// Delegated: one link per user, keyed to your own record
const session = await workwae.connectSessions.create({
  redirectUri: "https://app.example.com/mail/connected", // allowlisted first, under Settings
  providers: ["microsoft"],
  externalRef: user.id,
  loginHint: user.email,
  options: { calendarEnabled: true, contactsEnabled: true },
});

// App-only: your Entra app, consented by the directory's administrator
const connection = await workwae.orgConnections.create({
  kind: "microsoft_app",
  name: "Contoso",
  cloud: "global",
  credential: { type: "certificate", clientId, certificate, privateKey },
  directoryId,
});
await workwae.orgConnections.test({ connectionId: connection.id });
# Delegated: one link per user, keyed to your own record
session = workwae.connect_sessions.create(
    redirect_uri="https://app.example.com/mail/connected",  # allowlisted first, under Settings
    providers=["microsoft"],
    external_ref=user.id,
    login_hint=user.email,
    options={"calendar_enabled": True, "contacts_enabled": True},
)

# App-only: your Entra app, consented by the directory's administrator
connection = workwae.org_connections.create(
    kind="microsoft_app",
    name="Contoso",
    cloud="global",
    credential={
        "type": "certificate",
        "client_id": client_id,
        "certificate": certificate,
        "private_key": private_key,
    },
    directory_id=directory_id,
)
workwae.org_connections.test(connection_id=connection.id)
What maps where

From EWS operations to Workwae calls.

Workwae has its own mail, calendar and contact model, the same for Gmail, Microsoft 365 and IMAP. It is not a pass-through of Graph.

Operation mapping
In EWS In Workwae
FindItem, GetItem on messages messages.list and messages.get; ranked full-text search over the synced index
UpdateItem (read state and similar) messages.update, written to the provider and the index
CreateItem and SendItem for mail outbox.create, with scheduling and undo
Calendar items calendarEvents.create, calendarEvents.update and calendarEvents.respond
GetUserAvailability availability.find
Contacts contacts.create and contacts.update
SyncFolderItems, GetEvents The change feed, paged by transaction id
Streaming, pull and push subscriptions Signed webhooks with a delivery log and replays
Impersonation with full_access_as_app An organization connection with application permissions
Not offered, with or without EWS

Workwae has no calls for these. Microsoft’s parity roadmap says which have a Graph equivalent.

  • Public folders
  • Archive mailboxes and mailbox import and export
  • Inbox rules, out-of-office settings and MailTips
Stored ids need new keys

Workwae ids are new. Keep the mailbox’s externalRef as your link, and key messages by Workwae id after each account’s first sync, which ends with account.initialized.

FAQ

Questions teams ask.

Will our users have to sign in again?

Yes, in most cases. An EWS grant is a different permission from the Graph ones Workwae uses, so users sign in through hosted connect, or an administrator consents once for an organization connection. If your own app already holds Graph consent for some users, you can import their refresh tokens with accounts.create instead (your own OAuth app).

Can we keep running EWS while we migrate?

Only if the customer’s tenant admin allows it. Admins can re-enable EWS until April 1, 2027, in Baseline Security Mode or with Set-OrganizationConfig -EWSEnabled $true. After that there is no switch.

Does Workwae connect to on-premises Exchange?

Not over EWS. A server that allows IMAP and SMTP connects as an IMAP account. Microsoft is not retiring EWS in Exchange Server.

Do we need our own Entra app registration?

No, but your own app puts your product name on the consent screen and is the way to connect GCC High and DoD, where each cloud needs its own registration (GCC High and DoD).

What replaces EWS streaming notifications?

Webhooks. Workwae keeps the Graph subscriptions and delta queries, with a backstop poll, and sends your endpoint signed events such as message.created. Verify them with parseWebhook in the TypeScript SDK or parse_webhook in the Python SDK (webhooks guide).

Which Microsoft clouds work?

Commercial and GCC, GCC High and DoD over Graph. 21Vianet mailboxes connect over IMAP and SMTP, because Graph mail sync does not run there yet (Microsoft 365).

Are the SDKs stable?

Not yet. @workwae/sdk for TypeScript is at 0.1.0-alpha and workwae for Python is at 0.1.0a2, and Workwae is in early access.

Ready to move off EWS?

Tell us what your integration calls and which Microsoft clouds your customers are in, and we will plan the move with you.