First we need to install two Exchange Assemblies with the NuGet Package Manager, in order to have an API to access the Exchange Web Services (EWS) and therefore have access to an Exchange Mailbox.

So right-click on your Project and from the context menu click on Manage NuGet Packages ...


Search for Exchange Web Services and select the Microsoft.Exchange.WebServices package, I will install the latest version v2.2.0 at the moment of this post.

As you can read in the description, this package contains an API to access the Exchange Web Services (EWS). EWS itself provides access to mailbox data stored in Exchange Online and on-premises versions of Exchange starting with Exchange Server 2007.

https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/start-using-web-services-in-exchange


The Exchange Web Services (EWS) Managed API provides a .NET Framework interface to EWS in Exchange Online, Exchange Online as part of Office 365, and versions of Exchange starting with Exchange Server 2007 Service Pack 1 (SP1).



After installing this package, we have two new references (Assemblies) in our project.

  • Microsoft.Exchange.WebServices
  • Microsoft.Exchange.WebServices.Auth


To check what packages are installed in your project, you can switch to the Installed register in the NuGet Package Manager. In the Updates register you can check if there is new version of your installed packages.


Furher we need to add a new reference to the System.Configuration assembly. The assembly and class provides access to configuration files for client applications.

We use this class to access the App.config file described below.

ConfigurationManager Class
https://docs.microsoft.com/en-us/dotnet/api/system.configuration.configurationmanager



So let’s start with the programming part.

I will first configure the App.config file from our program which will contain the variables we need to control the access of our mailboxes.

More about the App.config file you will find under :
Use Visual C# to store and retrieve custom information from an application configuration file
https://docs.microsoft.com/en-us/troubleshoot/dotnet/csharp/store-custom-information-config-file

The App.config files replaces the legacy INI Files.


We need to add a new child element to our App.Config XML file named appSettings.

  <appSettings>
    <add key="EWS_URL" value="https://mail.braintesting.de/EWS/Exchange.asmx" />
    <add key="MBX" value="jane.doe@braintesting.de" />
    <add key="Password" value="Testing.2020" />
    <add key="MailFrom1" value="marcus.rath@braintesting.de" />
    <add key="MailFrom2" value="John.Doe@braintesting.de" />
    <add key="MailFrom3" value="not.defined@domain.tld" />
    <add key="MailFrom4" value="not.defined2@domain.tld" />
    <add key="Path" value="C:\Temp\attachments\" />
    <add key="Filename" value="sample.xlsx" />
  </appSettings>




Now we create a new class which contains all the code to access the Exchange Web Service (EWS) and therefore our Exchange Mailbox Account.


Inside our new class named Exchange.cs, we first add a few new using directives, so that we not to have write the whole namespaces in front of our commands.

using Microsoft.Exchange.WebServices.Data;
using System.Net;
using System.Configuration;


The System.Net.Http assembly, which will be referenced by default in our .Net Framework Console Application, provides a programming interface for modern HTTP applications, including HTTP client components that allow applications to consume web services over HTTP and HTTPS components that can be used by both client and servers for parsing HTTP headers.

Our Application uses this API to perform the login for the Exchange Web Services (EWS) URL which in my case is https://mail.braintesting.de/EWS/Exchange.asmx

System.Net.Http
https://www.nuget.org/packages/System.Net.Http/


Further we need to declare inside this class a new private variable service from the type ExchangeService which comes from our installed package and assembly Microsoft.Exchange.Web.Services.

private ExchangeService service;


After declaring the service variable we can create the service object which represents the destined Exchange Mailbox.

protected void UseExchangeService(string userEmailAddress, string userPassword)
        {

            string sEwsUrl;
            sEwsUrl = ConfigurationManager.AppSettings.Get("EWS_URL");


            service = new ExchangeService
            {
                Credentials = new NetworkCredential(userEmailAddress, userPassword),
                Url = new Uri(sEwsUrl)
            };

        }



Also we must add a function which will search the Inbox for mails from our specific sender address.

public void SearchItems()
        {
            string sMBX;
            sMBX = ConfigurationManager.AppSettings.Get("MBX");

            string sPassword;
            sPassword = ConfigurationManager.AppSettings.Get("Password");

            string sMailFrom1;
            sMailFrom1 = ConfigurationManager.AppSettings.Get("MailFrom1");

            string sMailFrom2;
            sMailFrom2 = ConfigurationManager.AppSettings.Get("MailFrom2");

            string sMailFrom3;
            sMailFrom3 = ConfigurationManager.AppSettings.Get("MailFrom3");

            string sMailFrom4;
            sMailFrom4 = ConfigurationManager.AppSettings.Get("MailFrom4");

            UseExchangeService(sMBX, sPassword);

            // Bind the Inbox folder to the service object.
            Folder inbox = Folder.Bind(service, WellKnownFolderName.Inbox);

            // The search filter to get unread email.
            // SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));

            // The search filter to get Mail from notification@pkmserver.de
            SearchFilter sf1 = new SearchFilter.ContainsSubstring(EmailMessageSchema.From, sMailFrom1);
            SearchFilter sf2 = new SearchFilter.ContainsSubstring(EmailMessageSchema.From, sMailFrom2);
            SearchFilter sf3 = new SearchFilter.ContainsSubstring(EmailMessageSchema.From, sMailFrom3);
            SearchFilter sf4 = new SearchFilter.ContainsSubstring(EmailMessageSchema.From, sMailFrom4);

            SearchFilter.SearchFilterCollection searchFilterCollection = new SearchFilter.SearchFilterCollection(LogicalOperator.Or);
            searchFilterCollection.Add(sf1);
            searchFilterCollection.Add(sf2);
            searchFilterCollection.Add(sf3);
            searchFilterCollection.Add(sf4);


            ItemView view = new ItemView(1000);

            //FindItemsResults<Item> findResults = service.FindItems("System.Message.DateReceived:01/01/2011..01/31/2011", iv);
            FindItemsResults<Item> findResults = service.FindItems(WellKnownFolderName.Inbox, searchFilterCollection, view);

            foreach (Item item in findResults)
            {
                GetAttachmentsFromEmail(item.Id);

            }

            System.Threading.Thread.Sleep(5000);

        }



Finally in this class we nee to add a function, which will pick up the attachment from the previously mails in search results, and saved it to the path we set in the App.config file. Further this function will also move the message to the deleted items folder in the mailbox.

 public void GetAttachmentsFromEmail(ItemId itemId)
        {
            string sMBX;
            sMBX = ConfigurationManager.AppSettings.Get("MBX");

            string sPassword;
            sPassword = ConfigurationManager.AppSettings.Get("Password");

            string sPath;
            sPath = ConfigurationManager.AppSettings.Get("Path");

            string sFilename;
            sFilename = ConfigurationManager.AppSettings.Get("Filename");

            UseExchangeService(sMBX, sPassword);

            // Bind to an existing message item and retrieve the attachments collection.
            // This method results in an GetItem call to EWS.
            EmailMessage message = EmailMessage.Bind(service, itemId, new PropertySet(ItemSchema.Attachments));
            // Iterate through the attachments collection and load each attachment.
            foreach (Attachment attachment in message.Attachments)
            {
                if (attachment is FileAttachment)
                {
                    FileAttachment fileAttachment = attachment as FileAttachment;
                    // Load the attachment into a file.
                    // This call results in a GetAttachment call to EWS.

                    // save with fix name sample.xlsx
                    fileAttachment.Load(sPath + sFilename);
                    Console.WriteLine("File attachment name: " + fileAttachment.Name);
                    message.Delete(DeleteMode.MoveToDeletedItems);

                }
                else // Attachment is an item attachment.
                {
                    ItemAttachment itemAttachment = attachment as ItemAttachment;
                    // Load attachment into memory and write out the subject.
                    // This does not save the file like it does with a file attachment.
                    // This call results in a GetAttachment call to EWS.
                    itemAttachment.Load();
                    Console.WriteLine("Item attachment name: " + itemAttachment.Name);
                }
            }


        }


Below you will find a few links from Microsoft where the Microsoft.Exchange.WebServices class is well documented in detail.


The final step is to call the SearchItems() function in our Exchange.cs class from the Main method of the Program.cs class which is the entry point of our application and the first method that is invoked.

 static void Main(string[] args)
        {
            Exchange ex = new Exchange();
            ex.SearchItems();
        }





Testing

Here we can see a mail from myself to the mailbox from Jane Doe which includes an attachment in form of an Excel file.


Now we will run the application in order to see if it will access the mailbox from Jane Doe and searches for all mails in the Inbox where the sender is marcus.rath@braintesting.de as in the App.config listed under the MailFrom property.

Further we set in the App.config file the destination path where to save the attachment and also a Filename property in which the attachment should be renamed.

So go to the Debug menu and click on Start Debugging or press F5 to run the application.

The files was successfully exported from Jane’s Inbox and saved to the Path we set in the App.config file C:Tempattachments


Further in Jane’s Mailbox the mail was moved to the deleted messages folder as instructed by our application.

public void GetAttachmentsFromEmail(ItemId itemId)
{
……
message.Delete(DeleteMode.MoveToDeletedItems);





Links

Attachments and EWS in Exchange
https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/attachments-and-ews-in-exchange

Search for and delete messages in Exchange Server
https://docs.microsoft.com/en-us/exchange/policy-and-compliance/ediscovery/delete-messages?view=exchserver-2019

Get attachments by using EWS in Exchange
https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-get-attachments-by-using-ews-in-exchange#bk_saveitemattach

Getting attachments by using the EWS Managed API 2.0
https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633665(v%3Dexchg.80)

Filtering on ContainsSubstring by using the EWS Managed API 2.0
https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633645(v=exchg.80)?redirectedfrom=MSDN