Google Contacts to Outlook/Office 365 Sync
On a schedule, the flow syncs Google Contacts into the organization's Office 365 contacts (or a shared mailbox), mapping fields, handling additions and updates, and avoiding duplicates via a stored ID map. Keeps Microsoft and Google address books aligned for hybrid teams.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
This flow keeps Microsoft and Google address books aligned for hybrid teams. On a 12-hour schedule it reads the full Google Contacts list and mirrors each contact into the organization's Office 365 / Outlook contacts, mapping fields and avoiding duplicates via a stored ID map (a Dataverse ledger). New contacts are created; already-mirrored contacts are updated in place — so Outlook never accumulates duplicates and stays current with Google.
Why it matters: Teams that maintain contacts in both ecosystems suffer drift and double entry. A scheduled, idempotent sync with a cross-id ledger gives a single, governed Outlook address book without manual re-keying.
Status: Built — ships Off (demo). Going live requires only authorizing the four connections and setting the environment-variable values.
Use Case
A team using both Google and Microsoft wants one consistent contact list in Outlook. Operations / IT Admins schedule the sync; the Google Contacts connector has no usable new-contact trigger, so a scheduled diff against a Dataverse ID map provides exactly-once create + idempotent update.
Flow Architecture
Recurrence
Recurrence (Hour/12)Every-12h sync cadence (no native new-contact trigger).
Initialize varContactFolder
Initialize Variable (String)Outlook contact folder — flowlibs_ContactFolder (default contacts).
Initialize varTargetMailbox
Initialize Variable (String)Target mailbox UPN — flowlibs_TargetMailbox (portability/documentation).
Initialize varMapTable
Initialize Variable (String)Dataverse ID-map entity set — flowlibs_MapTable (default flowlibs_contactmaps).
Initialize varSyncedCount
Initialize Variable (Integer)Counter of new contacts created this run.
Initialize varUpdatedCount
Initialize Variable (Integer)Counter of existing contacts updated this run.
Get My Profile
Office 365 Users — MyProfile_V2Resolve the running sync identity / target mailbox owner.
List Google Contacts
Google Contacts — PeopleApiListContactsV4Read all Google contacts (body/connections).
Apply to each Contact
Foreach (concurrency 1)Process each contact sequentially.
Compose Primary Email
ComposeLowercased primary email = dedup / cross-id key.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_ContactFolder | String | contacts | Outlook contact folder (well-known name contacts or a folder id) to write into. |
| flowlibs_TargetMailbox | String | you@yourcompany.com | Target mailbox UPN (documentation/portability; the V2 contact ops write to the connection owner's mailbox /me). |
| flowlibs_MapTable | String | flowlibs_contactmaps | Entity-set name of the Dataverse stored ID map. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| Google Contacts | shared_googlecontacts | PeopleApiListContactsV4 |
| Office 365 Users | shared_office365users | MyProfile_V2 |
| Office 365 Outlook | shared_office365 | ContactPostItem_V2 ContactPatchItem_V2 |
| Microsoft Dataverse | shared_commondataserviceforapps |
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Shared mailbox target
- Swap ContactPostItem_V2/ContactPatchItem_V2 for the shared-mailbox contact ops and point them at flowlibs_TargetMailbox to populate a shared address book instead of the connection owner's mailbox.
- Bidirectional sync
- Add a reverse flow (Outlook contact change -> Google Contacts CreateContact) keyed on the same ID map. Note the Google connector has no update op, so reverse updates create a new Google contact unless handled via the Graph People API (HTTP + OAuth).
- More fields / photos
- Extend the item/* mapping (addresses, IM addresses, categories) and add UpdateMyContactPhoto to sync photos.
- Dedup against existing Outlook contacts
- Before Create Outlook Contact, add ContactGetItems_V2 with a $filter on email to skip contacts already present in Outlook but missing from the ledger.
- Sync cadence
- Adjust the Recurrence interval; the ID map keeps create exactly-once and update idempotent regardless of frequency.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Primary email (dedup key)
Lowercased primary email used as the cross-id key.
EXPR.02Ledger filter (is-new check)
OData filter then is-new test against the ID map.
EXPR.03Display name
Display name, falling back to the email.
EXPR.04Company / title
First organization name and title.
EXPR.05Email addresses (Outlook item)
Outlook contact emailAddresses element shape.
EXPR.06Home phones (required array)
Phone carried in the required homePhones array.
EXPR.07Stored Outlook id / map id
Reads the stored cross-id and map row id.
Customize & download
Generate a ready-to-import copy of this solution with your environment-variable values baked in — available on Base, Pro, or Team.
Upgrade to customize
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.