Synchronize Google calendar with Outlook with Microsoft Power Automate

Having multiple calendars that are not synchronized often causes scheduling issues. To solve this problem, I built a Microsoft Power Automate flow that synchronize Google calendar with Outlook. The flow is free / open-source, and here I explain how to set it up, configure and use it.

Originally posted on 2024-01-14, updated on 2024-03-02 to reflect the changes made in version 0.9 of the flow.

Introduction

Sometimes having multiple different calendars is inevitable, but it comes at a cost: when scheduling an appointment, you need to check all calendars to determine your availability, and other people (who can access just one of your calendars) may send event invitations at time slots where you are not actually available.

I had this problem with two Outlook 365 calendars, which is why I previously built a Power Automate flow that synchronizes two Outlook calendars. You can learn more about it in this blog post. However, more and more users also asked me whether I could build an equivalent solution to synchronize Outlook with Google calendars, so I built one and present it in this post.

Features

This Power Automate flow essentially performs two uni-directional synchronizations (from Google to Outlook, and vice versa). For every calendar event in one calendar, it creates a corresponding “SyncBlocker” event in the other calendar. “Uni-directional” in this context means that any changes you make to the SyncBlocker events are overwritten by the flow on the next synchronization cycle.

The flow runs in regular intervals and has many configuration options:

  • Synchronization trigger: on which week days, and which hours of the day should the flow run
  • (Optional) Prefix for SyncBlocker events: e.g. a string like “SyncBlocker: “. This helps you to disambiguate real events (that you created in your calendar) from those created by the Power Automate flow
  • Synchronization interval, you can specify the number of future days to be synchronized
  • Configurable SyncBlocker event reminders (off, on with some configurable minutes)
  • Limit synchronizing to those source Outlook events that have a specific response type
  • Obfuscation of the title or body of the event in either the Google or Outlook calendar (for privacy reasons)
  • Uni-directional synchronization in just one direction (e.g. only Google to Outlook)
  • Optional exclusion of source events that have no other attendees (e.g. doctor appointment reminders)
  • Optional category for SyncBlocker events created in Outlook

Limitations

For technical reasons, there are also a few limitations, which are listed here.

Step-by-step instructions to synchronize Google calendar with Outlook

To set up my Power Automate flow in your own Power Automate account, you need a corresponding subscription that allows importing flows as a zip archive.

Try this first if you have a free Microsoft account

Before you continue reading the rest, I recommend that you first verify whether the import flow feature is actually available to you. Open https://make.powerautomate.com, and click My flows → Import → Import package (legacy). If you see an Upload form, you are good to go, otherwise you’ll need to pay for a subscription.

First, set up the connections for your Outlook 365 and Google calendar account. On https://make.powerautomate.com, click on “… More” → Connections, then “+ New connection” at the top, then search for “Office 365 Outlook” and follow the on-screen instructions. Repeat this for the “Google calendar” connection.

Next, download my flow as zip archive from https://github.com/MShekow/outlook-google-calendar-sync.

Back on https://make.powerautomate.com, click My flows → Import → Import package (legacy), click the Upload button, and choose the zip archive you just downloaded. In the form that is shown afterwards, click the links in the “IMPORT SETUP” column to fix any errors. The first row lets you configure the name of the flow that is created, and in the second and third row, you need to choose the two connections you created earlier. Finally, click on “Import”.

Next, we need to activate the flow, because it has been imported in a deactivated state (in which we cannot even trigger a test run). To do so, open the imported flow and click the “Turn On” button in the top menu.

Next, we need to tune the settings of the flow and test whether it works as expected. Click on “Edit” to open the flow editor, then click on all those actions at the top that start with “Setting: …” and change the values as desired. I added an explanatory note to each setting that explains what it does. I highly recommend that you initially leave the “Days to sync” setting at 1 day. Save the flow, and click on “Test” to run it.

In the very first run, it is important to get the names / IDs of the calendars right (see action blocks “Setting: name of Outlook calendar” and “Setting: id of Google calendar”), or the synchronization won’t work. Open your first run of the flow, and expand the “Check that calendars exist” action at the bottom. If you do not see any green checkmarks in the “If yes” half, the calendar names are not configured correctly yet. In this case, scroll up again, and expand the action blocks “Get calendars of Outlook account” or “Get calendars of Google account”. Take a look at their output (click Show raw outputs for better readability): in case of Outlook, the body > value > name field tells you the name of your Outlook calendar, as returned by the Outlook APIs. Please note that the returned name may differ from the calendar’s name shown in the Outlook UI. If the value of body > value > name of the calendar you want to synchronize is not “Calendar”, you need to open the edit view of the flow again and update its actions “Setting: name of Outlook calendar” respectively. Save the flow (top menu) and then run another test.

If the calendar names / IDs are correct, you should verify (in Outlook and Google) that your calendar events have been synchronized properly. For each event you should see blocker events in the other calendar (whose attendees field contains a fictional email address that embeds the correlation ID of the source event). Only if this is the case you should increase the “Days to sync”, and save+test the flow again.

Please be aware that Power Automate is rather slow, so it’s totally normal if a test run takes a long time (e.g. 15 minutes for synchronizing 30 days). You can also check which write-operations were done by a flow execution, by expanding the “Check that calendars exist” box and then click on the very bottom action of that specific flow execution.

Power Automate limitations

Depending on your Power Automate plan, there are various limitations (see documentation). Most notably, the “Action request limits” limit the number of triggerable actions to 10’000 per day. Power Automate counts the requests in the worst possible way (for you): exemplary, if you have a for-each-loop that loops over 5 items, and you define two actions inside the loop, Power Automate counts these as 5*2=10 action requests. Consequently, you need to experiment with the number of days you want to sync, and the number of flow executions per day, to stay below the action request limits.

Conclusion

This flow is quite new and not as battle-tested yet as the Outlook <-> Outlook variant. If you run into any issues, let me know in the comments, or create a GitHub issue.

You can also use my Power Automate flow to synchronize more than two calendars: just duplicate the flow, always use the same Outlook calendar, and use a different sync blocker prefix for each flow duplicate. The result is a star-shaped synchronization pattern, e.g. synchronizing calendar A with B, A with C and A with D. Similarly, you could always use the same Google calendar as the center of the star-shape.

9 thoughts on “Synchronize Google calendar with Outlook with Microsoft Power Automate”

  1. This worked really well the only issue i have is some zoom meetings scheduled in google takes up the location field so when its sync’ed to outlook the zoom meeting information is gone. Is there another place we can shove the ID? maybe append it to the bottom of the description or store it in google sheets?

    Reply
    • Glad that it is helpful.

      As for your question: appending it to the body will have the problem that it will be difficult to parse it from the body in a reliable way. And as you suggested, you can of course store the calendar ID mapping somewhere else entirely, such as a Google sheet (or Excel sheet), but I doubt that you can search inside that sheet as efficiently as the (currently implemented) search in the array. So, ultimately: “no dice”.

      Reply
      • Thanks Marius!
        Any recommendations on how to sort out the Zoom information stored in location field issue then? I’m trying to pick this flow apart to figure it out but its definitely more complicated than i imagined.

        Reply
        • Hmm, I quickly checked how the calendar event looks like that contains a Zoom invitation. It seems that the URL is both in the “location” field and is also part of the event summary field, so the information _is_ there, you should be able to join, it’s just less convenient.

          The only thing I can imagine you could do is to decide that you do not want the event summary/body synchronized at all, using the event summary/body instead of the location field. But I won’t be able to support you any further on how to implement this, I’m afraid.

          Reply
  2. Hi, thank you so much for providing this flow. It really helps me a lot.
    Everything is working as desired. Well almost everything…
    When I look up the date in google calendar, every entry has a location like “040000008200E00074C5B7101A82E00800000000000000000000000000000000000000001A0000007643616C2D556964010000004553544154453131303537343600”
    I only use this flow for pushing outlook calendar entries to my google cal so my wife can look up them in case.
    Is there a way I can omit the location?
    Thanks a lot and have a nice day. best, Falko

    Reply
    • Nope, that is expected behavior, and this limitation is explicitly listed:

      > The location field value is not synchronized, because the synchronization algorithm uses it to correlate events, i.e., the ID of the source event is stored in the location of the target / SyncBlocker event.

      Reply
  3. instead of having “SB: Blocker” to hide text, is there a way instead to tick the box for “private” on the outlook side?

    Reply
    • Sure, just modify the Power Automate flow and configure the sensitivity field of the blue Outlook actions that create or update events.

      Reply

Leave a Comment