Unable to locate specific message by SingleValueExtendedProperty

395 Views Asked by At

I have an app that tries to send an email message using the Microsoft Graph, and then retrieve that same message for importing some information into our database.

After researching this, the suggested trick is to attach unique piece of information to the message, and then search for the message using that value. In the case of the Graph/Mail, that method is a SingleValueExendedProperty.

I have this working in both the application, and in a LinqPad environment for testing. However I'm getting rare instances of the Graph not being able to locate the email. I traced the message down and was able to locate the InternetId via message tracing and have been trying to troubleshoot the problem.

I can get the message from the Graph SDK using the InternetId, but not by using the SingleValueExtendedProperty, even though I can see the exact value of the SingleValueExtendedProperty on the message when retrieved via the InternetId, and it only seems to be a problem with specific messages sent, not all of them. I'm beginning to suspect it's a problem with the Graph?

The GUIDs used in my code are just internal logging/event Ids, so they aren't really secret, the rest of the sensitive information has been left out for security reasons.

Below is the code I'm using for my testing in LinqPad using the packages Microsoft.Graph 3.12.0, Microsoft.Identity.Client 4.18.0, and Microsoft.Graph.Auth 1.0.0-preview5

Guid propertyNamespace = Guid.Parse("75CF8950-C01A-4D68-850D-13E7E49C12C0"); //Just a random GUID to use as my namespace

async Task Main()
{
    //Just including these to be thorough, obviously the real values are omitted for security
    var clientId = "";
    var tenantId = "";
    var secret = "";

    var clientApplication = Microsoft.Identity.Client.ConfidentialClientApplicationBuilder.Create(clientId)
            .WithAuthority(Microsoft.Identity.Client.AzureCloudInstance.AzurePublic, tenantId)
            .WithClientSecret(secret)
            .Build();

    var authProvider = new Microsoft.Graph.Auth.ClientCredentialProvider(clientApplication);
    var graphClient = new Microsoft.Graph.GraphServiceClient(authProvider);

    //This will locate the message correctly
    var messageById = await GetMessage(graphClient, "[email protected]", "[email protected]"); //Fake `InternetId`, but you get the point

    //This will not find the message
    var messageByProperty = await GetMessage(graphClient, "[email protected]", "EventId", Guid.Parse("6c105c1e-cb55-4ba4-90f6-ac2b01084a54"));

    var propertyFoundById = messageById.SingleValueExtendedProperties.Single();
    $"'{propertyFoundById.Id}' '{propertyFoundById.Value}'".Dump("propertyFoundById");
    $@"singleValueExtendedProperties/Any(ep: ep/id eq 'String {propertyNamespace:B} Name {"EventId"}' and ep/value eq '{Guid.Parse("6c105c1e-cb55-4ba4-90f6-ac2b01084a54")}')".Dump("Expression when filtering by property");

    /*
    The above two Dump() statements will spit out the following strings respectively

    'String {75cf8950-c01a-4d68-850d-13e7e49c12c0} Name EventId' '6c105c1e-cb55-4ba4-90f6-ac2b01084a54' 

    singleValueExtendedProperties/Any(ep: ep/id eq 'String {75cf8950-c01a-4d68-850d-13e7e49c12c0} Name EventId' and ep/value eq '6c105c1e-cb55-4ba4-90f6-ac2b01084a54') 
    */
}

///<summary>A method to locate a message by searching with the SingleValueExtendedProperties</summary>
private async Task<Microsoft.Graph.Message> GetMessage(Microsoft.Graph.GraphServiceClient graphClient, string mailbox, string propertyName, Guid propertyValue)
{
    var message = (await graphClient.Users[mailbox].MailFolders["SentItems"].Messages.Request()
        .Filter($@"singleValueExtendedProperties/Any(ep: ep/id eq 'String {propertyNamespace:B} Name {propertyName}' and ep/value eq '{propertyValue}')")
        .Expand($"singleValueExtendedProperties($filter=id eq 'String {propertyNamespace:B} Name EventId')")
        .GetAsync())
        .SingleOrDefault();
    return message;
}

///<summary>A method to locate a message by searching with the InternetId<summary>
private async Task<Microsoft.Graph.Message> GetMessage(Microsoft.Graph.GraphServiceClient graphClient, string mailbox, string internetId)
{
    var message = (await graphClient.Users[mailbox].MailFolders["SentItems"].Messages.Request()
        .Filter($@"internetMessageId eq '<{internetId}>'")
        .Expand($"singleValueExtendedProperties($filter=id eq 'String {propertyNamespace:B} Name EventId')")
        .GetAsync())
        .SingleOrDefault();
    return message;
}

I checked the SingleValueExtendedProperty of the message it finds by the InternetId, and compared it to the filter expression used in the other method and the details look identical. This seems to be unique to very few email message (approx 3 out 175) sent by the application however, since if I send a new one in LinqPad

var message = new Microsoft.Graph.Message();
message.SingleValueExtendedProperties = new Microsoft.Graph.MessageSingleValueExtendedPropertiesCollectionPage();
message.SingleValueExtendedProperties.Add(new Microsoft.Graph.SingleValueLegacyExtendedProperty { Id = $"String {propertyNamespace:B} Name {propertyName}", Value = Guid.Parse("11111111-2222-3333-4444-555555555555").ToString() });
/* Other fields excluded for brevity */
await graphClient.Users["[email protected]"].SendMail(message, true).Request().PostAsync();

Then both of the GetMessage() methods I use above (one using InternetId, the other by the SingleValueExtendedProperties) will both find the same message when I look for this new message

I would love to know if anyone else encountered this issue, or if there's a known issue I should be aware of? I'm tempted to try official support options, but I am loathe to try getting a real person because of how specific the problem appears to be.

0

There are 0 best solutions below