Migrating Dynamics 365 Attachments in Bulk to Azure Blob Storage using Logic Apps

Storage in Dynamics 365 is expensive if we have a lot of attachments. This problem could be easily solved by using the free attachment management solution in the App Source which is currently supported and works well.

However, if you are migrating from an on prem environment to online you want to move all the attachments in bulk.  The Attachment Management solution does provide this feature but it's limited as it runs inside CRM

Since, it's not realistic to keep pushing the button to migrate attachments if we have thousands of them, we need an alternative solution (pushing a button always reminds me of the Lost TV series :))

This leaves us with either custom coding the migration or leveraging the Dynamics 365 connector and Azure Blob Storage connector in logic app or maybe there is a third party tool out there that does the same thing as well.

In this blog, I will walk through creating a logic app for migrating email attachments.

Let's start the logic app by defining the trigger, in this case I'm using the Recurrence trigger and than the D365 connector. Let's specify the filter to use the filesize.

The file size will be greater than zero when the attachment is stored on the database.

I'm using the List records for the above step 'Get Email Attachments'.

Make sure to rename your steps before adding any actions underneath them. once an action is added you will not be able to rename it unless you delete the sub action step.

Since both the Activity Mime Attachment and the Attachment entity have the same display name, you could use the below reference to distinguish them.

The next step is to retrieve the attachment record that has the actual body. We have to do this as the Activity Mime Attachment entity in the logic app connector does not expose the body field when it does the retrieve. The Activity Mime Attachment has the AttachmentId field and we will use that as a filter to retrieve the attachment record

This would again add another for each but since it's always one record(1:1 mapping between the ActivityMime and the Attachment entity) it should not cause much impact.

Let's add the step for 'Create Blob' action under the Azure storage connector.

Notice that the blob name format matches the format used by the Attachment Management solution. This is required so the plugins can use this to retrieve them from storage within Dynamics 365.

Note:- For the Blob content you might have to use convertBase64ToBinary in the expression content for the Blob content field. Dynamics stores the Body as base 64 string. The Create Blob action might not work properly with directly specifying base64 string and when you download the blob from the blob storage, you will not be able to open the file. So make sure to properly test this before running this on large amount of records.

Now after the blob is created we need to remove the attachment from D365 which in turn sets the filesize to zero. We do this by making an Update record action on the D365 connector.

However, the update record action does not expose the body field attribute for the Activity Mime Attachment entity. In order to solve this we set a reference point in our logic app using the Attachment Number below.

Now let's switch to the code view of our logic app. Remove the attachmentnumber and other attributes shown below.


Replace them with just the body attribute and set it to null.

Let's hit save and switch back to the designer view. We should now see the body attribute being set on the update step.

Make sure to run the above update step only after the attachment is successfully created as a blob in your blob storage. This can be setup by clicking the 'Configure run after' setting as shown in the first 'Remove Attachment ...' picture above

That's it! We are now good to go, let's run the app and you will see the attachments moving over.

Note :- You might have to tweak the recurrence and the count of the records based on your needs.

Also, after running a few records make sure that when you download or open an attachment, you are seeing the actual attachment content. To verify that the attachments are no longer in D365 run an advanced find or web api query using the REST builder. Make sure there are no records with file size greater than zero.

Although this logic app only covers the activitymimeattachment entity, you could follow the same steps for the Note(annotation) entity. The annotation entity is straightforward since it's just one entity and is easier to implement. You might have to use base64ToBinary function in the expression if directly using the base64 documentbody field does not work.

Let me know if there are other ways you have used to migrate the attachments in bulk.