Rory
Rory

Reputation: 41807

ErrorMissingEmailAddress error when accessing other user's Exchange mailbox by EWS

I'm using EWS Managed API to read emails from Inbox and subfolders. When I connect as the mailbox owner with username & password auth it all works fine, but when I connect as a service account using windows auth I get an error when accessing the subfolders. The service account has been granted Full Access to the mailbox it's connecting to. The service account doesn't have its own mailbox. The error is:

Problem encountered while retrieving the email from exchange. Microsoft.Exchange.WebServices.Data.ServiceResponseException: 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.
   at Microsoft.Exchange.WebServices.Data.ServiceResponse.InternalThrowIfNecessary()
   at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute()
   at MyMethod_That_Calls_ExchangeServer_FindItems(folderId, view)

This is a pretty common error to get when you're using delegate access to a mailbox (i.e. not connecting to a mailbox you own) and you connect to a Well Known mailbox without specifying the mailbox owner. There's an easy fix to that: you create a FolderId object using a Mailbox object with the primary smtp address of the mailbox you want to connect to, e.g.

var theMailboxEmailAddress = "[email protected]";
var folderId = new FolderId(WellKnownFolderName.Inbox,
                      new Mailbox(theMailboxEmailAddress);
var items = myExchangeService.FindItems(folderId, anItemView);

However, my case isn't that easy. I am specifying the mailbox where I can but I'm getting the error when I'm calling FindItems on the subfolder. There's no way to specify the mailbox when accessing the subfolder, because it should work without that.

According to this article ('Explicit access and EWS') the suggested method is:

When I look at the EWS trace I can see that there are no DistinguishedFolderIds being sent in my FindItems() request. Here is the call that fails:

Trace type: EwsRequest
Trace message: <Trace Tag="EwsRequest" Tid="13" Time="2016-10-13 12:50:05Z" Version="15.00.0913.015">
  <?xml version="1.0" encoding="utf-8"?>
  <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
      <t:RequestServerVersion Version="Exchange2010_SP2" />
    </soap:Header>
    <soap:Body>
      <m:FindItem Traversal="Shallow">
        <m:ItemShape>
          <t:BaseShape>IdOnly</t:BaseShape>
          <t:AdditionalProperties>
            <t:FieldURI FieldURI="item:Subject" />
            <t:FieldURI FieldURI="item:DateTimeReceived" />
            <t:FieldURI FieldURI="message:IsRead" />
            <t:FieldURI FieldURI="message:From" />
            <t:ExtendedFieldURI DistinguishedPropertySetId="InternetHeaders" PropertyName="X-MyApp-MailId" PropertyType="String" />
          </t:AdditionalProperties>
        </m:ItemShape>
        <m:IndexedPageItemView MaxEntriesReturned="6" Offset="0" BasePoint="Beginning" />
        <m:SortOrder>
          <t:FieldOrder Order="Ascending">
            <t:FieldURI FieldURI="item:DateTimeReceived" />
          </t:FieldOrder>
        </m:SortOrder>

<!-- Note below there's no DistinguishedFolderId, so nowhere to specify the mailbox -->

        <m:ParentFolderIds>
          <t:FolderId Id="AAMkAGU2NWRkNjYxLTI3YjktNDFkMi04ZmNlLWI0M2FmMGVmYzBhYwAuAAAAAAD/Z9M6ia69S5l65fo6tjEaAQAoQBtCK9L9S4ux7hB0Qcw/AAAIZFKVAAA=" />
        </m:ParentFolderIds>


      </m:FindItem>
    </soap:Body>
  </soap:Envelope>
</Trace>

Here's the failure response:

Trace type: EwsResponse
Trace message: <Trace Tag="EwsResponse" Tid="13" Time="2016-10-13 12:50:05Z" Version="15.00.0913.015">
  <?xml version="1.0" encoding="utf-8"?>
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
      <h:ServerVersionInfo MajorVersion="15" MinorVersion="0" MajorBuildNumber="847" MinorBuildNumber="31" Version="V2_8" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <m:FindItemResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
        <m:ResponseMessages>
          <m:FindItemResponseMessage ResponseClass="Error">
            <m:MessageText>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.</m:MessageText>
            <m:ResponseCode>ErrorMissingEmailAddress</m:ResponseCode>
            <m:DescriptiveLinkKey>0</m:DescriptiveLinkKey>
          </m:FindItemResponseMessage>
        </m:ResponseMessages>
      </m:FindItemResponse>
    </s:Body>
  </s:Envelope>
</Trace>

In the example above I was specifying ExchangeServerVersion Exchange2010_SP2 but I've tried also with Exchange2013. I'm connecting to an Exchange 2013 server.

A colleague tried the same thing using EWSEditor and got the same error. I've not double-checked that yet, but if so it suggests an EWS problem or an easy mistake to make when using the API.

Also posted on MSDN forums here.

UPDATE 13-Oct-16:

Based on this Handling delegation-related errors in EWS in Exchange article I'm now wondering if this is a 'by design' limitation of Exchange. i.e. that if you want to look in non-well-known folders in an inbox you must have a mailbox, else it can't manage the permissions or something like that. In that article it says for ErrorMissingEmailAddress occurs when "Make a request using a delegate account that does not have a mailbox." and to handle it by "Adding a mailbox to the delegate’s account."

I'll check tomorrow whether adding a mailbox to the service account (which is otherwise not used at all) resolves the problem.

Upvotes: 0

Views: 1634

Answers (1)

Wiz
Wiz

Reputation: 416

Inspecting the (Microsoft.Exchange.WebServices.Data) FolderId class, it shows that when writing the Xml for the request, I believe it should include the Mailbox entry. It also shows that if you ToString() it, it should return the Folder ID and Mailbox ID. I'd suggest confirming the mailbox you are getting with "new Mailbox(theMailboxEmailAddress)" is not null and the value is what you expect. I also noticed the GetXmlElementName only returns DistinguishedFolderId when the FolderName within FolderId has a value - which from what I can see so far only occurs when the FolderId is created with a uniqueId string instead of a WellKnownFolderName.

    internal override string GetXmlElementName()
    {
        if (!this.FolderName.HasValue)
        {
            return "FolderId";
        }
        return "DistinguishedFolderId";
    }

    public FolderId(WellKnownFolderName folderName, Mailbox mailbox) : this(folderName)
    {
        this.mailbox = mailbox;
    }

    internal override void WriteAttributesToXml(EwsServiceXmlWriter writer)
    {
        if (this.FolderName.HasValue)
        {
            writer.WriteAttributeValue("Id", this.FolderName.Value.ToString().ToLowerInvariant());
            if (this.Mailbox != null)
            {
                this.Mailbox.WriteToXml(writer, "Mailbox");
                return;
            }
        }
        else
        {
            base.WriteAttributesToXml(writer);
        }
    }

    public override string ToString()
    {
        if (!this.IsValid)
        {
            return string.Empty;
        }
        if (!this.FolderName.HasValue)
        {
            return base.ToString();
        }
        if (this.Mailbox != null && this.mailbox.IsValid)
        {
            return string.Format("{0} ({1})", this.folderName.Value, this.Mailbox.ToString());
        }
        return this.FolderName.Value.ToString();
    }

Update 1: I was still able to grab a quick trace. These were my results from some quick test code:

folder = New FolderId(WellKnownFolderName.Inbox)
Dim v As New ItemView(10, 0, OffsetBasePoint.Beginning)
Dim f As FindItemsResults(Of Item) = oService.FindItems(folder, v)

    <m:ParentFolderIds>
      <t:DistinguishedFolderId Id="inbox" />
    </m:ParentFolderIds>



Dim box As New Mailbox(mailboxAddress)
folder = New FolderId(WellKnownFolderName.Inbox, box)
Dim v As New ItemView(10, 0, OffsetBasePoint.Beginning)
Dim f As FindItemsResults(Of Item) = oService.FindItems(folder, v)

  <m:ParentFolderIds>
      <t:DistinguishedFolderId Id="inbox">
        <t:Mailbox>
          <t:EmailAddress>****mailboxAddress****</t:EmailAddress>
        </t:Mailbox>
      </t:DistinguishedFolderId>
    </m:ParentFolderIds>

Update 2:

Confirmed that when using FolderId created with a uniqueId string, the trace is:

    <m:ParentFolderIds>
      <t:FolderId Id="AQMkADY5YmEzNGJmLTljN2QtNDIwNS1hMWU2LTg4ADM4NDAzMDcxMGEALgAAA83F9dM/SH5Lnnw/6ftMMB0BANfWBWp5+bpGsBoSfk3Km5IAAAINKgAAAA==" ChangeKey="AQAAABYAAADX1gVqefm6RrAaEn5NypuSAAC8Vr7C" />
    </m:ParentFolderIds>

Upvotes: 0

Related Questions