I can’t recall how many times I have come across a requirement to programmatically read emails from an Exchange Server mailbox and take some action based on the presence of new messages. The component reading the emails can read the mail content, parse its contents and transmit the data to other downstream systems. In this blog I’m going to take a look at one way we can do this.

Objective

In my scenario there was a requirement to develop a program to retrieve mails from an Exchange mailbox and, based on a specific criteria, send the email to multiple users based on an distribution list identifier. Listed below are the steps, I intended to follow:

  1. Use an efficient calling mechanism to poll for new email based on a given criteria
  2. Read any new email messages
  3. Transform the received email to an SMTP-friendly message to be sent to a list.

Solution

I developed my solution in .Net, using C# as the language of preference, hooking into the Exchange Web Services (EWS) Managed API as the polling endpoint and using simple SMTP endpoints to send mails. Let’s look at the solution in a little more detail.

Prerequisites / Preparation

  1. Open Visual Studio and create a new Console Application
  2. Install Exchange Web Services (EWS) Managed API from NuGet Package Manager
  3. Add reference for System.Configuration (to support application configuration).

Create a connection to a given mailbox

When creating connections to an Exchange mailbox we need to know the version of the source Exchange environment. The code to connect will differ based on the target environment. At time of writing, the EWS managed API supports the following Exchange Server versions:

  1. Exchange 2007 SP1
  2. Exchange 2010 (inc. SP1 & SP2)
  3. Exchange 2013 (inc. SP1)

Use the latest (Exchange 2013 SP1) if you are using this to connect with Exchange Online in Office 365. Below is the code to connect and get a service instance attached to an Office 365 mailbox.

Remember to have a AutodiscoverRedirectionUrlValidationCallback function to enable SSL communication.

The sample below shows how to connect to a local Exchange 2007 environment.

Read email using the created service instance

Once the connection is up and running this is relatively straightforward. The process can be summarised as follows:

  1. Specify the mailbox folder to read messages from (i.e. inbox)
  2. Specify the source mailbox email identifier
  3. Specify any search filters
  4. Specify the aggregation criteria (OR / AND)
  5. Specify the maximum number of messages to be retrieved
  6. Retrieve message identifiers using the service instance.

… and some sample code …

Now we have the message identifiers, but the message body and other basic properties are missing. A second call will need to be made to the server retrieve extended properties for each message. Here is the code for that process:

Prepare the outbound mail for sending

I used a temporary custom object to transform the email from the EWS calls prior to sending. Below is the code used to create the class and the mapping logic.

The code below transforms the temporary mail object into a valid SMTP mail, validates the email identifiers, the mail needs to broadcast to, filters out the invalid mail Ids (if found) and sends the mails in multiple allowed batches.

last but not least.. Send the mail..

[code language=”csharp”]

mail.SendMail();

[/code]

Happy Mailing!!!

Category:
Application Development and Integration, Exchange, Office 365
Tags:
, ,

Join the conversation! 21 Comments

  1. Hi. I am looking at your post and I have a question: Is the Exchange Web Services (EWS) Managed API something you would install on your client to broker a programmatic connection to Exchange? Or is this an add-on you would need to install on your Exchange server?

    • Hi Francois,

      Exchange API is a set of assemblies that will be used by the connecting application (in this case an .NET app). The API is available as a NuGet package while developing with Visual Studio.

  2. Hi Vibhu, Thanks for this nice article.
    I just want to know what will be the values for below two configurations?
    ConfigurationManager.AppSettings[“User”].ToString()
    ConfigurationManager.AppSettings[“MailBox”].ToString()
    Is this will be the same user email id?
    I just want to create an application to read all emails into a particular email id after login with emailid and password. I tried this sample code and i am getting “The Autodiscover service couldn’t be located.”.

    Any help will be much appreciated!
    thanks
    Jaison

    • Hi Jalson, The “User” value is the username, that the code shall be using to read the mailbox. The “Mailbox” is the email address of the mailbox, that the code intends to read. Hope that answers the query…

  3. Hi, currently your using EWS Application API to send Email. If in case we are in process of migrating application from exchange 2007 to exchange 2013 / office365. From where these logs can be exported how many applications connecting through EWS for sending email. As we have (SMTP, IMAP, POP)

  4. Hi, thanks for this detailed article.
    there are thousands of emails In my inbox (80,000 email) and i want read them FIFO i.e. to start with the old one and finish with the most recent one. Hoe to do so? Thanking you in advance.

  5. Use Autodiscover to set the URL endpoint.
    means what ?

    • Hi Krishna, By autodiscover, the code will be able to “discover” the most relevant web service end point. (in effect the exposed web service URL by exchange administrators, associated with the exchange)

  6. plz sir Can share your code

  7. I have a process that runs under service account not associated with a mailbox.
    After switching to Exchange 2013 the process started failing with the following error “When making a request as an account that does not have a mailbox, you must specify the mailbox primary SMTP address for any distinguished folder Ids.” I use delegation and it works for all mailbox-enabled accounts. any idea what might be going on ?
    appreciate any help
    Thank you
    Julia

    • Hi Julia,
      Please help with more details as the point of error, mailbox permissions with your service account. In addition, also please confirm if the mailbox in question as more than one SMTP addresses associated (one of them being primary).

      • Thank you for getting back to me!

        Below is the stripped down code.
        It worked fine accessing functional mailboxes on Exchange 2010
        However, when the functional mailboxes were converted to exchange 2013, we got a problem running it under service accounts that don’t have associated mailbox. It still runs fine under regular accounts with associated mailboxes.
        Both, regular and service accounts have full access and permissions to functional mailboxes

        I think maybe there are security changes that were introduced in Exchange 2013. but i couldn’t find anything about it.

        int cnt =2;
        ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
        FolderId folderId = new FolderId(WellKnownFolderName.Inbox, new Mailbox(SMTPaddressAsAppearsInAD));
        SearchFilter.SearchFilterCollection sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And);
        sf.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
        FindItemsResults findResults = service.FindItems(folderId,sf, new ItemView(cnt));

      • Hi Julia,

        Have you tried changing the exchange service version?

        ExchangeService(ExchangeVersion.Exchange2010_SP1)

  8. Hi Mr Vibhu,
    Thank you for this documentation, I need to know 3 things:
    1- In my case I need to save the data each time an email is received in an SQL table. So how to make this code always running in the background? So whenever an email is received, it will be directly saved.
    2- If one day we decided to stop saving data, how can we make it?
    3- Where we have to implement this code? Could it be by creating a restful service?

    Thank you in advance

  9. I am not able to see any code on this page, except mail.SendMail();

    • The GitHub Gist code snippets are embedded. It’s likely either 1) a security/privacy setting on your browser, 2) DNS issue or 3) a network routing issue that’s blocking yourself seeing that content.

  10. Hello, great article. How do parse encrypted emails? Is there a way to get the private key for the mailbox in order to decrypt the emails?

  11. Hello,

    Thanks for the article. I have currently the problem that I get the message “The Autodiscover service couldn’t be located.”. We are currently under Office365 and VS2017, Would you have any ideas how to solve this?

    Many thanks for your replay.
    Aschwin Luijten

  12. In case of bounce back emails how we could get original mail.

Comments are closed.