# Google Workspace and Microsoft 365 detection

> How isBusinessEmail detects Google Workspace and Microsoft 365, finds the Entra tenant ID and federation, and what the detection deliberately does not do.

Source: https://isbusinessemail.com/docs/workspace-detection

Integrations like Google Workspace admin APIs, Shared Drives, Microsoft Graph with admin consent, SharePoint and OneDrive for Business need the customer's company to **have a tenant**. A signup on `jane@gmail.com` or `jane@outlook.com` doesn't have one. Knowing this at signup lets you pick the right connector, warn early, and avoid onboarding that stalls three steps later.

Detection works **per company domain**, from public DNS and Microsoft's public discovery documents. It never looks up the individual person.

## What you get

```json
"workspace": {
  "google_workspace": { "detected": true, "evidence": ["mx_google", "dkim_google"] },
  "microsoft_365": { "detected": false, "tenant_id": null, "auth": null, "identity_provider": null, "evidence": [] },
  "other_suite": null,
  "pending": false
},
"integrations": { "google_workspace_ready": true, "microsoft_365_ready": false }
```

Field-by-field meanings are in [Response fields](https://isbusinessemail.com/docs/response-fields#workspace).

## Google Workspace

| Evidence | Strength | Notes |
|---|---|---|
| MX `aspmx.l.google.com` (and `alt1`–`alt4`) or `smtp.google.com` | Strong | Consumer Gmail uses `gmail-smtp-in.l.google.com` instead, which is how we tell Workspace from Gmail |
| DKIM key at `google._domainkey.<domain>` | Strong | `google` is the default selector in the Workspace admin console. Catches Workspace **behind a mail gateway** such as Proofpoint or Mimecast, where MX doesn't show Google. |
| SPF `include:_spf.google.com` | Medium | Authorizes Google to send for the domain |
| `google-site-verification=` TXT | Weak | Also used by Search Console, so on its own it proves little |
| Legacy `ghs.googlehosted.com` CNAMEs | Weak | Older Google Sites / custom URL setups |

Google doesn't publish a tenant ID or a public per-domain discovery endpoint, so Google detection is DNS-only.

## Microsoft 365 / Entra ID

| Evidence | Strength | Notes |
|---|---|---|
| OpenID discovery for the domain returns a tenant | Strong | `https://login.microsoftonline.com/<domain>/v2.0/.well-known/openid-configuration` is public and documented. It gives the **tenant ID**, `tenant_region_scope` and the cloud instance. |
| MX `<domain>.mail.protection.outlook.com` | Strong | Exchange Online. Consumer Outlook.com uses `*.olc.protection.outlook.com` |
| TXT `MS=ms…` | Medium | Domain verification for Microsoft 365 |
| `autodiscover`, `enterpriseregistration`, `enterpriseenrollment`, `lyncdiscover` records | Medium | Exchange, device registration/enrollment, Skype for Business / Teams |
| SPF `include:spf.protection.outlook.com` | Medium | Authorizes Exchange Online to send |

### Managed vs federated

For a detected tenant we ask Microsoft's home-realm discovery which kind of sign-in the domain uses, with a **placeholder** username, never the real person:

- `auth: "managed"`: users sign in with Entra ID directly.
- `auth: "federated"`: sign-in is redirected to another identity provider, reported in `identity_provider` (Okta, ADFS, Ping…), with reason `ms_federated`.

Federation matters for onboarding: the admin you need may be in the IdP team, and SSO flows will hop through the IdP.

### What the tenant ID is good for

The tenant ID lets you skip the "which organization?" step in Microsoft flows. For example, an admin-consent link scoped to the customer's tenant:

```text
https://login.microsoftonline.com/{tenant_id}/v2.0/adminconsent
  ?client_id={your_app_id}
  &scope=https://graph.microsoft.com/.default
  &redirect_uri={your_redirect_uri}
  &state={csrf_token}
```

See the [onboarding use case](https://isbusinessemail.com/use-cases/onboarding-integrations) and the [Microsoft tenant lookup tool](https://isbusinessemail.com/tools/microsoft-tenant-lookup).

## Other suites

MX hosts also reveal Zoho Mail, Proton, Fastmail, Yandex 360 and Microsoft 365 resellers. These show up in `workspace.other_suite` with reason `mx_other_suite`. The domain is still `business`; it just won't work with Google- or Microsoft-only integrations.

## Mixed setups are normal

- **Microsoft identity, Google mail** (or the reverse): both `detected` can be `true`.
- **Mid-migration**: MX points one way, DKIM and SPF the other.
- **Behind a gateway**: MX shows Proofpoint or Mimecast, and DKIM/SPF reveal the real suite.

Check both booleans; don't assume one excludes the other.

## Timing and caching

- Detection runs inline when the Microsoft tenant lookup answers within 0.7 s. Otherwise the response comes back with `workspace.pending: true`, the lookup finishes in the background, and the next check returns the full result.
- Pass `workspace=false` to skip the Microsoft tenant lookup when you only need the category.
- Results are cached per domain for 30 days, so most checks return detection instantly.

## What it does NOT do

We made deliberate choices here.

- **No per-person lookups.** We don't call Microsoft's `GetCredentialType`, probe Google sign-in, or use SMTP `RCPT TO` to test whether `jane@` exists. These techniques are user enumeration: they reveal whether a specific person has an account, break the providers' terms, get IP ranges blocked, and are unreliable (catch-all domains, greylisting, throttling).
- **Not a license check.** A tenant existing doesn't mean this person has a Microsoft 365 or Workspace license, or that every user is on it.
- **Not an admin check.** We can't tell you whether the person signing up can grant admin consent. Plan for "invite your admin" flows.
- **No guarantee.** DNS can be stale, split or deliberately unusual. Treat detection as a strong hint for UX and routing, and confirm when the user actually connects.

## Try it

- [Google Workspace checker](https://isbusinessemail.com/tools/google-workspace-checker)
- [Microsoft tenant lookup](https://isbusinessemail.com/tools/microsoft-tenant-lookup)
- Test addresses `workspace@test.isbusinessemail.com` and `m365@test.isbusinessemail.com` ([Test addresses](https://isbusinessemail.com/docs/test-addresses))
