Search code examples
xmlsoapwsdlexchangewebservicessoaplite

EWS SOAP Requests failing


I am using PERL and SOAP::Lite to make soap calls to MS Exchange Web Services. I have already figured out authenticating and am using an Oauth token to make the calls. I am trying to call GetInboxRules which is documented here.

Basically the call needs to look like this.

<?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_SP1" />
  </soap:Header>
  <soap:Body>
    <m:GetInboxRules>
      <m:MailboxSmtpAddress>[email protected]</m:MailboxSmtpAddress>
    </m:GetInboxRules>
  </soap:Body>
</soap:Envelope>

My first attempt used the following code:

my $client = SOAP::Lite->service('file://home/auth/work/src/ben/services.wsdl')->proxy('https://outlook.office365.com/EWS/Exchange.asmx');
$client->readable(1)->autotype(0)->outputxml('true');
$client->ns('http://schemas.microsoft.com/exchange/services/2006/messages', 'm');

my $ua = $client->schema->useragent;
$ua->default_header('Authorization' => $auth_header);
$ua->default_header('Content-Type' => 'application/xml');
$client->schema->useragent($ua);

$client->transport->http_request->headers->push_header('Authorization'=> $auth_header);

# WITH URI
my $som = $client->call('GetInboxRules', SOAP::Data->name('MailboxSmtpAddress')->value('[email protected]')->uri('http://schemas.microsoft.com/exchange/services/2006/messages'));

This produced the following XML along with a 500 internal server error stating:

"The request failed schema validation: The element 'GetInboxRules' in namespace 'http://schemas.microsoft.com/exchange/services/2006/messages' has invalid child element 'MailboxSmtpAddress'. List of possible elements expected: 'MailboxSmtpAddress' in namespace 'http://schemas.microsoft.com/exchange/services/2006/messages'"

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
    soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <m:GetInboxRules>
      <MailboxSmtpAddress>[email protected]</MailboxSmtpAddress>
    </m:GetInboxRules>
  </soap:Body>
</soap:Envelope>

I am already setting the name space but to try and remedy this I specified the names space for the MailboxSmtpAddress element by adding a uri specification to it my $som = $client->call('GetInboxRules', SOAP::Data->name('MailboxSmtpAddress')->value('[email protected]')->uri('http://schemas.microsoft.com/exchange/services/2006/messages'));

which produced:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope
    soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:namesp3="http://schemas.microsoft.com/exchange/services/2006/messages"
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap:Body>
    <m:GetInboxRules>
      <namesp3:MailboxSmtpAddress xmlns:namesp3="http://schemas.microsoft.com/exchange/services/2006/messages">[email protected]</namesp3:MailboxSmtpAddress>
    </m:GetInboxRules>
  </soap:Body>
</soap:Envelope>

followed by a 400 Bad Request response. I am guessing that the bad request response is because of the url included in the MailboxSmtpAddress tag but I don't know how else to specify the namespace.

This is my first time working with SOAP so any suggestions would be very much appreciated.


Solution

  • A saint came to my rescue and presented me with the following code:

    my $client = SOAP::Lite
        ->readable(1)
        ->proxy('https://outlook.office365.com/EWS/Exchange.asmx')
        ->ns( 'http://schemas.microsoft.com/exchange/services/2006/types', 'typ')
        ->ns( 'http://schemas.microsoft.com/exchange/services/2006/messages', 'mes')
        ->envprefix('soapenv')
        ->autotype(0);
    
    $client->serializer->{'_attr'}{'{http://schemas.xmlsoap.org/soap/envelope/}encodingStyle'} = undef;
    
    
    $client->transport->default_header('Authorization' => $auth_header);
    $client->transport->default_header('X-AnchorMailbox' => '[email protected]');
    $client->transport->default_header('X-OWA-ExplicitLogonUser' => '[email protected]');
    
    my @header = (
        SOAP::Header->name('typ:RequestServerVersion')->attr({'Version' => 'Exchange2015'}),
        SOAP::Header->name('typ:ExchangeImpersonation')->value(\SOAP::Header->name('typ:ConnectingSID')
            ->value(\SOAP::Header->name('typ:SmtpAddress')->value('[email protected]')))
    );
    
    my @param;
    my $method;
    
    @param = (
         SOAP::Data->name('mes:MailboxSmtpAddress', '[email protected]'),
         );
    
    $method = SOAP::Data->name('mes:GetInboxRules');
    
    my $response = $client->call($method => (@param, @header));
    
    print Dumper($response);
    

    This resulted in the namespace tag being placed on the elements being passed to the method call and also corrected some issues I had with the formatting of the header.

    The following is the XML that came from that code:

    <soapenv:Envelope
        xmlns:mes="http://schemas.microsoft.com/exchange/services/2006/messages"
        xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:typ="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">
      <soapenv:Header>
        <typ:RequestServerVersion Version="Exchange2015" />
    
        <typ:ExchangeImpersonation>
          <typ:ConnectingSID>
            <typ:SmtpAddress>[email protected]</typ:SmtpAddress>
          </typ:ConnectingSID>
        </typ:ExchangeImpersonation>
      </soapenv:Header>
    
      <soapenv:Body>
        <mes:GetInboxRules>
          <mes:MailboxSmtpAddress>[email protected]</mes:MailboxSmtpAddress>
        </mes:GetInboxRules>
      </soapenv:Body>
    </soapenv:Envelope> 
    

    This produced a successful response from Microsoft.