Search code examples
c#asp.net-coremicrosoft-graph-apimailkit

read email from office 365 in .net core


I want to read my Office 365 emails connected to my Azure account in a .net core environment. When I try to access my application on Azure and read my emails with the code below, it gives the "Authentication Failed" error. I will be giving you my permissions in the application below. Can you help me find out where the problem is? Api Permissions: Microsoft Graph: User.Read(Delegated), IMAP.AccessAsUser.All(Delegated) Office 365 Exchange Online: IMAP.AccessAsApp(Application)

My Code:

public async Task<List<ReceivedEMails>> ReadEmailsAsync()
{
    var emailMessages = new List<ReceivedEMails>();

    try
    {
        // OAuth2 configuration
        var clientId = _configuration["EmailSettings:ClientId"];
        var tenantId = _configuration["EmailSettings:TenantId"];
        var clientSecret = _configuration["EmailSettings:ClientSecret"];
        var userEmail = _configuration["EmailSettings:EmailAddress"];
        var scope = new string[] { "https://outlook.office.com/.default" };

        // Get Access Token
        var cca = ConfidentialClientApplicationBuilder.Create(clientId)
            .WithClientSecret(clientSecret)
            .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}/v2.0"))
            .Build();

        var result = await cca.AcquireTokenForClient(scope).ExecuteAsync();

        // Connect to IMAP server
        using (var client = new MailKit.Net.Imap.ImapClient())
        {
            await client.ConnectAsync("outlook.office365.com", 993, true);
            await client.AuthenticateAsync(new SaslMechanismOAuth2(userEmail, result.AccessToken)); //error:authentication failed.

            // Select inbox
            await client.Inbox.OpenAsync(FolderAccess.ReadOnly);

            var items = await client.Inbox.FetchAsync(0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId);

            foreach (var item in items)
            {
                var email = client.Inbox.GetMessage(item.UniqueId);

                emailMessages.Add(new ReceivedEMails
                {
                    EmailCode = email.MessageId,
                    EmailSubject = email.Subject,
                    EmailSender = email.From.Mailboxes.FirstOrDefault()?.Address,
                    EmailContent = email.TextBody,
                    CreatedDate = email.Date.DateTime
                });
            }

            await client.DisconnectAsync(true);
        }
    }
    catch (Exception ex)
    {
        throw new InvalidOperationException("Failed to read emails.", ex);
    }

    return emailMessages;
}

I want to read my emails in my outlook account in a .net core environment. The error I get is "Authenticated Failed"


Solution

  • Outlook Mail REST API is DEPRECATED now and is recommended to migrating existing apps to use Microsoft Graph.

    As announced on November 17, 2020, version 2.0 of the Outlook REST API has been deprecated. The v2.0 REST endpoint will be fully decommissioned in November 2022, and the v2.0 documentation will be removed shortly afterwards. Migrate existing apps to use Microsoft Graph. See a comparison to start your migration.

    When using Graph Api for listing message for a specific user, according to OP's code snippet var scope = new string[] { "https://outlook.office.com/.default" };, I'm afraid OP's trying to use Application API permission so that we should at least having permission Application: Mail.ReadBasic.All and add admin consent.

    enter image description here

    Then we can use client credential flow + Graph SDK for this api like below:

    using Microsoft.Graph;
    using Azure.Identity;
    
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "tenant_name.onmicrosoft.com";
    var clientId = "aad_app_id";
    var clientSecret = "client_secret";
    var clientSecretCredential = new ClientSecretCredential(
                    tenantId, clientId, clientSecret);
    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    
    var result = await graphClient.Users["{user-id}"].MailFolders["{mailFolder-id}"].Messages.GetAsync();