📧 Recipe · Exchange & Email
List Members of a Mail-Enabled Group Including Organizational Contacts
Resolve every recipient — users, guests, and org contacts — that receives mail sent to a distribution or mail-enabled group
Complexity
Intermediate
Impact
Exchange Online + Groups + Mail Flow + Microsoft Graph + Directory
Context
Why This Matters
When a user asks "who actually gets email when I send to group@contoso.com?", a simple member lookup is often not enough. Mail-enabled groups in Microsoft 365 can contain:
- User objects — internal employees with mailboxes
- Guest users — external B2B collaborators
- Other groups — nested distribution or security groups
- Organizational contacts (
orgContact) — external recipients synced from on-premises AD or created in Exchange, often representing vendors, partners, or shared aliases
Graph's /groups/{id}/members endpoint happily returns orgContact entries, but their displayName, mail, and proxyAddresses fields come back as null unless your app has OrgContact.Read.All. Admins chasing a "missing recipient" incident frequently hit this wall. This recipe walks through resolving every recipient behind a mail-enabled group, including the org-contact case.
Expected Outcomes
After running this recipe you will have:
- The group's object ID, display name, mail address, and group type (unified, security, distribution, mail-enabled security)
- A full list of direct members, with the object type for each (
user,group,orgContact,device) - Resolved display names and SMTP addresses for org-contact members (requires
OrgContact.Read.All) - A list of group owners (who can manage membership, and who receives NDRs in some configurations)
- Optional: flattened/transitive membership if the group contains nested groups
Risks & Considerations
Permission scope matters
Without OrgContact.Read.All, organizational contacts appear in /members responses but all their useful properties are null. Admins often misdiagnose this as "empty group" or "broken members". Grant the scope (admin consent required) before concluding the group is misconfigured.
Distribution vs. Microsoft 365 groups
For classic distribution lists (groupTypes is empty, mailEnabled: true, securityEnabled: false), Graph exposes membership read-only. To modify membership you must use Exchange Online PowerShell (Add-DistributionGroupMember), not Graph.
Nested groups and dynamic membership
Direct /members does not expand nested groups. Use /transitiveMembers to see every leaf recipient. Dynamic groups populate asynchronously — very recent rule changes may not be reflected.
Privacy
Enumerating recipients of an internal DL can expose sensitive org structure. Do not export full membership to external systems without approval, and redact guest/external contact addresses in tickets where possible.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| Group.Read.All | Read group properties and direct/transitive membership via Microsoft Graph. |
| GroupMember.Read.All | Alternative least-privilege scope that allows reading members without other group properties. |
| OrgContact.Read.All | Required to resolve displayName, mail, and proxyAddresses for organizational contacts that appear as group members. |
| User.Read.All | Resolve details for user members (UPN, mail, accountEnabled). |
| Directory.Read.All | Fallback broad read scope if the tenant has not granted the narrower scopes above. |
The fastest way to get this done — just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex CoAdmin
For End Users
How an employee would ask Dex for help