DawidPotgieter / Dynamics-CRM-Binary-Storage-Options

A Dynamics CRM plugin to transparently store attachment binaries outside CRM database. Azure Blob or File storage for instance.
GNU Affero General Public License v3.0
34 stars 15 forks source link

Attachments on email templates #17

Open charomps opened 5 years ago

charomps commented 5 years ago

When I create an email template with an attachment the plugin adds the attachment to azure fine but what it errors when using the email template to send to multiple contacts.

When sending the email it gets stuck in a pending state with an error on the attachment saying that it cannot find the specified attachment in azure.

Looking at the system jobs I can see that upon sending a quick campaign with an email template the BinaryStorageOptions.Plugin: Create of activitymimeattachment is triggering successfully, but the attachment is not appearing in azure causing the error to occur on sending the email.

If i send a single email with an attachment it works fine. Its just upon sending email templates.

Has anyone else come across this?

DawidPotgieter commented 5 years ago

Hi there,

I'm afraid I don't have time right now to test your scenario, but perhaps you can try this that I've got somewhere on the wiki :

Open the plugin registration tool and register a new step under BinaryStorageOptions.Plugin. Message = Retrieve Primary Entity = template Post Operation / Synchronous

Remember to add the secure and unsecure config xml.

You can test with just this, and you can add one more for "RetrieveMultiple" with the same settings.

Basically, this will tell CRM to use the plugin when reading templates, which is where I can see the email templates are stored at. I'm not certain whether your problem is on the read or create message, but I'm guessing it will actually be on the read.

Let me know how that goes.

Cheers.

Update.

Had a very quick look at this, and it seems the system creates new emails when you run a campaign. Since there's no plugins associated with campaigns, doesn't look like the email attachments work. I will see what I can do about this, can't give you a timeframe atm though...

DawidPotgieter commented 5 years ago

Update 2.

If you look in the V5 branch here :

https://github.com/DawidPotgieter/Dynamics-CRM-Binary-Storage-Options/blob/V5/Source/BinaryStorageOptions/Plugin.Retrieve.cs

I've added a new method :

private Tuple<int, byte[]> SearchForAttachment(IOrganizationService service, Providers.IBinaryStorageProvider storageProvider, Entity entity, string documentBodyAttributeKey, string fileNameAttributeKey)
{
    //This is a little bit of a hack, but there really isn't very many good options.
    //When there's an error loading an email attachment, there's a good chance that crm is requesting a duplicate of an existing attachment, as that's how it seems to be stored.
    //So, go through the list of activitymimeattachments pointing to the same attachment id, and see if you can get the binary data using that.
    using (OrganizationServiceContext context = new OrganizationServiceContext(service))
    {
        var attachmentId = ((EntityReference)(from ama in context.CreateQuery(CrmConstants.AttachmentEntityName)
                                                                                    where ((EntityReference)ama[CrmConstants.AttachmentEntityId]).Id == entity.Id
                                                                                    select ama[CrmConstants.AttachmentId]).FirstOrDefault()).Id;
        var activitymimeattachmentIds = (from ama in context.CreateQuery(CrmConstants.AttachmentEntityName)
                                                                            where (Guid)ama[CrmConstants.AttachmentId] == attachmentId
                                                                            select ama[CrmConstants.AttachmentEntityId])
                                                                            .ToList();

        foreach (Guid activitymimeattachmentId in activitymimeattachmentIds)
        {
            try
            {
                int fileSize = storageProvider.GetFileSize(activitymimeattachmentId, (string)entity.Attributes[fileNameAttributeKey]);
                byte[] data = storageProvider.Read(activitymimeattachmentId, (string)entity.Attributes[fileNameAttributeKey]);

                return new Tuple<int, byte[]>(fileSize, data);
            }
            catch { }
        }
    }
    return null;
}

And it's called in the catch block of the "HandleEntity" method above :

if (entity.LogicalName == CrmConstants.AttachmentEntityName)
{
    //Search for other attacments pointing to the same attachment id (not the activitymimeattachment).
    var otherData = SearchForAttachment(service, storageProvider, entity, documentBodyAttributeKey, fileNameAttributeKey);
    if (otherData != null && entity.Attributes.ContainsKey(fileNameAttributeKey))
    {
        if (entity.Attributes.ContainsKey(CrmConstants.FileSizeKey) &&
                (int)entity.Attributes[CrmConstants.FileSizeKey] == GenericConstants.EmptyBodyContentDataLength)
        {
            entity.Attributes[CrmConstants.FileSizeKey] = otherData.Item1;
        }

        if (entity.Attributes.ContainsKey(documentBodyAttributeKey) && 
                (string)entity.Attributes[documentBodyAttributeKey] == GenericConstants.EmptyBodyContent)
        {
            entity.Attributes[documentBodyAttributeKey] = Convert.ToBase64String(otherData.Item2);
        }
        return;
    }
}

You'll also need to add some constants in CrmConstants :

public const string AttachmentEntityId = "activitymimeattachmentid";
public const string AttachmentId = "attachmentid";

This seems to fix the reading issues I can see for campaign generated emails. It's a bit of a hack, but it seems to work.

Hope it helps.

DawidPotgieter commented 5 years ago

Hi there,

Did you try the fix? Can I close the ticket perhaps?