Search code examples
c#azureconsole-applicationexchangewebservices.net-4.8

The code for Microsoft.Exchange.WebServices version 2.2.1.0 is not working, even though the token is being generated


I have a development environment as below

  • Visual Studio 2022 .net version 4.8
  • Microsoft.Exchange.WebServices version 2.2.1.0
  • Microsoft.Exchange.WebServices.Auth version 15.0.0.0
  • Microsoft.Identity.Client version 4.63.0.0 and also I have Azure permission as below enter image description here

I have written code below that generates a Token, but when it reaches the line

var folders = _service.FindFolders(WellKnownFolderName.Inbox, new FolderView(10));

It throws error like Microsoft.Exchange.WebServices.Data.ServiceRequestException: 'The request failed. The remote server returned an error: (403) Forbidden.' Below is the full code

private static void ReadMailsFromExchangeServer()
{
    //  _service.Credentials = new WebCredentials("[email protected]", "qwerty", "tng");
    try
    {

        string token = GetAccessToken();

        ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2016)
        {
            Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx"),
            Credentials = new OAuthCredentials(token),
        }; // Use your EWS endpoint


        // Impersonate the user you want to act on behalf of
        _service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "[email protected]");
        // Set X-AnchorMailbox header to the SMTP address of the mailbox being accessed
        _service.HttpHeaders.Add("X-AnchorMailbox", "[email protected]");//[email protected]
        _service.HttpHeaders.Add("X-PreferServerAffinity", "true");
        var folders = _service.FindFolders(WellKnownFolderName.Inbox, new FolderView(10));
        foreach (var folder in folders)
        {
            Console.WriteLine(folder.DisplayName);
        }

    }
    catch (Exception ex)
    {

    }
}
        private static async void GetTokens()
        {
            // Using Microsoft.Identity.Client 4.22.0
            var cca = ConfidentialClientApplicationBuilder
                .Create(ConfigurationManager.AppSettings["appId"])
                .WithClientSecret(ConfigurationManager.AppSettings["clientSecret"])
                .WithTenantId(ConfigurationManager.AppSettings["tenantId"])
                .Build();

            var ewsScopes = new string[] { "https://outlook.office365.com/.default" };

            try
            {
                var authResult = await cca.AcquireTokenForClient(ewsScopes)
                    .ExecuteAsync();
                var ewsClient = new ExchangeService();
                ewsClient.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
                ewsClient.Credentials = new OAuthCredentials(authResult.AccessToken);
                ewsClient.ImpersonatedUserId =
                   new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "[email protected]");

                //Include x-anchormailbox header
                ewsClient.HttpHeaders.Add("X-AnchorMailbox", "[email protected]");


            }
            catch (Exception ex)
            {

            }
        }

Solution

  • Initially I got the same error when granted same permissions as you:

    enter image description here

    The error "The request failed. The remote server returned an error: (403) Forbidden" usually occurs of the application do not have required permissions to perform the action.

    Hence to resolve the error, you need to grant Office 365 Exchange Online full_access_as_app application type API permission to the Microsoft Entra ID application like below:

    enter image description here

    After granting the required API permission, I am able to fetch the folders successfully:

    namespace EWSIntegration
    {
        class Program
        {
            static async System.Threading.Tasks.Task Main(string[] args)
            {
                await ReadMailsFromExchangeServer();
            }
    
            private static async System.Threading.Tasks.Task ReadMailsFromExchangeServer()
            {
                try
                {
                    string token = await GetAccessToken();
    
                    ExchangeService _service = new ExchangeService(ExchangeVersion.Exchange2016)
                    {
                        Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx"),
                        Credentials = new OAuthCredentials(token),
                    };
    
    
                    // Impersonate the user you want to act on behalf of
                    _service.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "test @test.com");
                    // Set X-AnchorMailbox header to the SMTP address of the mailbox being accessed
                    _service.HttpHeaders.Add("X-AnchorMailbox", "test @test.com");
                    _service.HttpHeaders.Add("X-PreferServerAffinity", "true");
                    var folders = _service.FindFolders(WellKnownFolderName.Inbox, new FolderView(10));
                    foreach (var folder in folders)
                    {
                        Console.WriteLine($"Folder: {folder.DisplayName}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"An error occurred: {ex.Message}");
                }
            }
    
                    private static async Task<string> GetAccessToken()
            {
                string clientId = "ClientID";
                string clientSecret = "ClientSecret"; 
                string tenantId = "TenantID"; 
    
                try
                {
                    var cca = ConfidentialClientApplicationBuilder
                    .Create(clientId)
                    .WithClientSecret(clientSecret)
                    .WithTenantId(tenantId)
                    .Build();
                    var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
                    var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
                    return authResult.AccessToken;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"An error occurred while acquiring the token: {ex.Message}");
                    throw;
                }
            }
        }
    }
    

    enter image description here