Exchange Web Services (EWS)

Früher war MAPI/CDO der bevorzugte Weg, um an die Inhalte eines Exchange Servers (Postfach und öffentliche Ordner) zu kommen. Allerdings hat dieser Weg in der modernen Zeit diverse Einschränkungen. Als 16/32bit Applikation bzw. COM-DLL ist der Weg in die Zukunft nicht einfach. Zudem erfolgt die Kommunikation per RPC gegen den Postfachserver. HTTPS wäre aber viel besser. Mit Exchange 2000/2003 gab es einen Zwischenschritt, da über das Protokoll WebDAV ein Zugriff auf Inhalte per HTTPS möglich wurde. Besonders elegant war dies aber auch nicht und mit Exchange 2007 wurden erstmals die Webservices bereit gestellt, welche zukünftig alle anderen APIs (WebDAV, CDO, ExOLEDB und OWA Url Commmands) ersetzen sollen. Mit Exchange 2010 wurden dann eine ManagedAPI für .NET bereit gestellt, dass Entwickler sehr viel einfacher arbeiten können.

Funktionsumfang

Was sie mit Webservices heute schon abdecken können, zeigt ein Diagramm. Sie zeigt sehr gut, welche Funktionen schon in Exchange 2007 enthalten waren und dass Exchange 2007 SP1 den Exchange 2007 Funktionsumfang quasi komplettiert hat. Natürlich wurden die Webservices mit Exchange 2010 nochmal erweitert.


Quelle: TechEd UNC324 What's New in Exchange Web Services in Microsoft Exchange Server 2010, Autor Albert Kooiman

Das Ernsthaftigkeit zum Einsatz von Exchange Web Services von Microsoft ist klar und deutlich: Sehr viele Produkte und Programme setzen mittlerweile auf EWS auf z.B. Entourage für Mac Web Service Edition, die TransporterSuite, Project Server 2010 für Aufgaben und immer mehr andere Tools von Microsoft und Drittherstellern. Die eigenständige Seite Webservice liefert eine allgemeine Beschreibung.

Über die Exchange Web Services ist daher ein einfacher, internettauglicher, Plattformunabhängiger Zugriff auf Inhalte möglich. Per Webservice kann sich ihr Programm sogar informieren lassen, wenn sich in einem Ordner etwas ändert. Allerdings funktioniert das nur Asynchron und nur pro Ordner. Es ist daher kein Ersatz für die Storesinks von Exchange 2000/2003. Allerdings kann man über die SynchronizationAPI Änderungen sehr einfach ermitteln und darauf reagieren.

Exchange Web Services nutzen

Ehe es von Microsoft die "Managed API" zu den Exchange WebServices gab, muss man sich noch selbst die WSDL-Datei besorgen und sich Proxy-Klassen schreiben und sehr genau prüfen, welche Parameter an welcher Stelle eingesetzt werden sollen. All Links zum Einsatz ohne Managed API habe ich mittlerweile an das Ende der Seite verschoben. (Siehe Exchange 2007 Webservices ohne Managed API). Sie sind immer noch wichtig, wenn Sie mit Programmen auf Exchange zugreifen wollen, die nicht .NET unterstützen, z.B. Java, Unix etc. Ansonsten würde ich speziell für Einsteiger stickt dazu raten, die Managed API zu nutzen.

Die sind aber erst mal herunter zu laden und auf dem Client zu installieren, damit Sie diese auch nutzen können.

Exchange Web Services Managed API 1.0 (ca. 700kb)
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=c3342fb3-fbcc-4127-becf-872c746840e1

Die Installation muss auf den System erfolgen, von dem aus der Zugriff auf die Daten erfolgen soll. Es ist nicht mehr erforderlich, eine Anwendung oder zusätzliche API auf dem Exchange Server zu installieren.

Nach Abschluss der Installation gibt es aber kein Icon im Startmenü o.ä. Sie können dann in ihrem Projekt einfach die neuen DLLs einbinden und dann basierend darauf eine neue Instanz eines Objekts zu erstellen und für Diagnosezwecke das Tracing zu aktivieren.

using Microsoft.Exchange.WebSerivces.Data;
using Microsoft.Exchange.WebSerivces.Autodiscover;

/* ewsserver initialisieren */
ExchangeService ewsservice= new ExchangeService;
/* ewsserver initialisieren wenn Ziel Exchange 2007 ist*/
ExchangeService ewsservice= new ExchangeService(Exchange2007_SP1);

/* Optional Credentials angeben */
ewsservice.Credentials = new NetworkCredential("name", "pwd", "domain");

/*  bei Bedarf ein trace einschalten */
ewsservice.traceEnabled = true;

/*  URL definieren ODER per Autodiscover ermitteln */
service.Url = new Uri("https://servername/EWS/Exchange.asmx");
service.AutodiscoverUrl("mailadresse@domain.tld");

Powershell und EWS

Aus VBScript ist es nicht möglich, Managed-Code einfach aufzurufen. Aber Powershell erlaubt dies schon sehr einfach. Eine sehr gute Quelle hierfür ist das Blog von Glen Scales

Hier werde ich bald deutlich mehr Beispiele bringen. CDO ist tot, es lebe EWS

# Laden der Manages API-DLLs in den Prozessraum
[void][Reflection.Assembly]::LoadFile("C:\Program Files\Microsoft\Exchange\Web Services\1.0\Microsoft.Exchange.WebServices.dll")

# ews-Klasse instanzieren
$ewsservice = new-object Microsoft.Exchange.WebServices.Data.ExchangeService
# ews-Klasse instanzieren wenn zielsystem Exchange 2007 ist
$ewsservice = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1)

# Optional mit anderen Benutzerdaten anmelden
$ewsservice.Credentials = New-Object System.Net.NetworkCredential("username","passwort","domain")

Autodiscover und Umleitung

Ehe Outlook 2007 SP1 auch mit SRV-Records arbeiten konnte, konnte ein Admin also nur ein Zertifikat für "autodiscover.maildomain.tld" konfigurieren oder ohne SSL einen HTTP-Redirect machen. Das funktioniert mit Outlook 2007 schon sehr gut aber wer per Exchange Web Services darauf zugreifen will, muss eine "Callback"-Funktion einrichten, die die Rückfrage bezüglich der "Umleitung" behandelt.

Das geht mit Powershell 1.0 schon gar nicht und mit 2.0 ist die Komplexität für die MSXFAQ eher hoch. Sie sollten dann einfach die URL manuell angeben

$ewsservice.url = "https://exchangeserver/EWS/exchange.asmx

 

 

Postfachzugriff mit "Impersonation" über "ms-Exch-EPI-May-Impersonate"

Oft reicht es nicht per EWS einfach sein eigenes Postfach zu öffnen. So wird es immer Dienstkonten geben, die in Postfächer anderer Benutzer zugreifen müssen. Dazu gibt es wie bei MAPI ebenfalls drei Optionen

Der letzte Fall ist das Thema dieses Abschnitts. Da der erste CAS-Server schon die Anmeldung übernimmt und die Server untereinander "vertrauenswürdig" sind, ist damit ein Durchgriff auf alle Postfächer auch in anderen Standorten (CAS 2 CAS Proxy) möglich. Damit kann ich einem Konto das Recht geben, quasi als der angegebene Benutzer zu arbeiten, ohne sich explizit mit dessen Anmeldedaten zu authentifizieren. Dazu unterscheidet Exchange zwei fast gleichlautende Berechtigungen:

Diese beiden Berechtigungen sind also unabhängig von den üblichen "Vollzugriffs-Rechten" auf Postfächer zu sehen, wie diese auf Mailboxrechte beschrieben werden. Impersonation greift nur beim Zugriff über Webservices während die normalen Postfachrechte für den Zugriff über OWA, MAPI, CDO etc. erforderlich sind.

Die Einrichtung dieser Berechtigungen ist nur über die Powershell möglich. Hier am Beispiel eines CAS-Servers

Add-ADPermission `
  -Identity CAS1 `
  -User SVCUser`
  -extendedRight ms-Exch-EPI-Impersonation

Oder hier über eine Schleife, um alle CAS-Server auf einmal zu konfigurieren:

Get-ExchangeServer | where {$_.IsClientAccessServer -eq $TRUE} | ForEach-Object {Add-ADPermission -Identity $_.distinguishedname -User (Get-User -Identity SVCUser | select-object).identity -extendedRight ms-Exch-EPI-Impersonation}

Die Berechtigungen auf die Postfachdatenbank ist über folgenden Befehl möglich:

Add-ADPermission `
  -Identity SG1/MBDATABASE1 `
  -User SVCUser`
  --ExtendedRights ms-Exch-EPI-May-Impersonate

Oder auch hier wieder für den Zugriff auf alle Postfächer aller Datenbanken:

Get-MailboxDatabase | ForEach-Object {Add-ADPermission -Identity $_.DistinguishedName -User SVCUser -ExtendedRights ms-Exch-EPI-May-Impersonate}

Der Benutzer muss also auf dem CAS-Server das Recht bekommen, überhaupt Impersonation anfordern zu können und auf der Postfachdatenbank die Erlaubnis, mit Impersonation auf die Daten darin zuzugreifen. Das Konto darf zudem kein Administrator sein, da über die Gruppe der Administratoren auch hier wieder ein "DENY" dieses Rechte unterbinden würde.

Wenn die Vergabe von Berechtigungen auf der Datenbank zu weit gehen, kann natürlich ebenfalls über die Benutzer die Berechtigungen vergeben:

Add-ADPermission `
  -Identity "Mailbox"`
  -User SVCUser `
  -extendedRight ms-Exch-EPI-May-Impersonate

Hiermit kann dann das Dienstkonto auf das Postfach zugreifen.

Diese Funktion wird z.B. auch bei der Transporter Suite eingesetzt, damit diese alle Nachrichten in die Exchange Postfächer übertragen kann.

Wenn Sie nun über EWS diese Funktion nutzen wollen, dann müssen Sie natürlich den Web Services über Impersonation konfigurieren. hier ein Auszug:

ewsservice.impersonatedUserID = new impersonatedUserID(ConnectingIDType.SID,wert)
ewsservice.impersonatedUserID = new impersonatedUserID(ConnectingIDType.PrincipalName,wert)
ewsservice.impersonatedUserID = new impersonatedUserID(ConnectingIDType.SmtpAddress,wert)

Bei Exchange 2010 müssen Sie hier aber dem User auch die Rechte geben (RBAC)

EWS und Notification Services

Die Webservices öffnen noch einen netten Weg: eine Anwendung kann per Webservices eine "Pushbenachrichtigung" einstellen, d.h. der Exchange Server informiert die Anwendung darüber, wenn sich in einem Postfach z.B. etwas tut. Dazu muss die Anwendung selbst auch einen Webservice bereitstellen, welcher von Exchange dann "rückwärts" aufgerufen wird. Als Programmierer weise ich also Exchange an, von von meiner Anwendung angebotenen Webservice bei bestimmten Situationen aufzurufen. Suchen Sie nach

SubscribePullNotification

Sie müssen aber einen Listener entwickeln, welcher dann von Exchange aufgerufen (ebenfalls WebService) wird. Details finden Sie auch hier:

Wenn Sie alles richtig gemacht haben aber ihr Webservice dennoch nicht angesprochen wird, dann sollten Sie einen Blick ins Eventlog tun:.

Event Type:      Warning
Event Source:    MSExchange Web Services
Event Category:  Core
Event ID:        6
Description:
Unable to send a notification for subscription 
fsdfllkn4325kjbzuvjdj2sj1jshj2dk2kj3s1fefh13g4g4sjg34as3244=. (Send attempts: 3)
Event Type:      Error
Event Source:    MSExchange Web Services
Event Category:  Core
Event ID:        7
Description:
After 8 unsuccessful attempts to send a notification for subscription 
fsdfllkn4325kjbzuvjdj2sj1jshj2dk2kj3s1fefh13g4g4sjg34as3244=
K8=, subscription has been removed.
Event Type:      Warning
Event Source:    MSExchange Web Services
Event Category:  Core
Event ID:        5
Description:
Unable to send a notification for subscription 
fsdfllkn4325kjbzuvjdj2sj1jshj2dk2kj3s1fefh13g4g4sjg34as3244=
K8=. Will retry.

Die lange Zeichenkette ist in Realität eine Base64-codierte Binärdatei, die man zwar decodieren kann, aber viel mehr als den Servername und ein paar kryptische Zeichen sieht man nicht. Es ist aber zumindest ein Hinweis, wohin der Sink gehen sollte. Die Einträge sind übrigens auf dem CAS-Server hinterlegt und wenn ich den Entwicklern glauben darf gibt es keine einfache Möglichkeit eine Liste der aktiven Benachrichtigungen zu generieren.

Man kann allerdings die IIS-Logs durchsuchen, wer, wann ein "Subscribe" auf den Exchange Web Services macht, d.h. im IISLog einfach mal nach "ews/exchange.asmx?SoapAction=Subscribe" suchen.

https://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=931885&SiteID=17
For push notifications, you need to write your own web service that implements the NotificationService.wsdl interface. Then you subscribe to receive notifications using the EWS Subscribe web method with a PushSubscriptionRequest sub-element. You will notice that the PushSubscriptionRequestType surfaces a status frequency (how often you want to be alerted of changes) and a URL which is the URL of YOUR web service. Then EWS will call the SendNotification web method on your service with the changes. You can unsubscribe by responding to the SendNotification web method with a subscription status of "Unsubscribe".

Exchange 2007 Webservices ohne Managed API

Eine Echtzeitverarbeitung mit der Option, eine Änderung des Clients zu verhindern oder synchron andere Funktionen durchzuführen ist mit Webservices scheinbar nicht möglich.

Hier nur eine kleine Auswahl von Links. Die MSDN-Seite ist sicher die beste Quelle.

EWS.DLL als Proxyklasse

Normalerweise nutzt ein Entwickler WSDL, um von einem Webservice die unterstützten Schnittstellen zu erfahren. Dazu muss man aber zur Entwicklungszeit natürlich zugriff auf den Webservice haben. Und nicht alle Entwicklungsumgebungen unterstützen direkt die Einbindung der WSDL-Informationen. Man kann daher die Beschreibung in einer DLL "einpacken", so dass auch andere Umgebungen eine elegante Unterstützung bei der Entwicklung erlauben.

Eleganter weise hat Glen Scales schon wieder die Arbeit getan, die Microsoft im BLOG nicht getan hat und stellt eine EWS.DLL direkt bereit

EWS.DLL zum Download
http://msgdev.mvps.org/exdevblog/ewsutil.zip.

Mit dieser EWS ist es dann auch in Powershell seht einfach auf Exchange 2007 Ressourcen zuzugreifen. Hier ein Beispiel, um sich per Powershell auf den Posteingang zu verbinden.

[void][Reflection.Assembly]::LoadFile("C:\Programme\msxfaq\EWSUtil.dll")

$mbMailboxEmail = "admin@msxfaq.local"
$ewc = new-object EWSUtil.EWSConnection($mbMailboxEmail,$false,$null,$null,$null,$null)

$dTypeFld = new-object EWSUtil.EWS.DistinguishedFolderIdType
$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::inbox

$mbMailbox = new-object EWSUtil.EWS.EmailAddressType
$mbMailbox.EmailAddress = $mbMailboxEmail
$dTypeFld.Mailbox = $mbMailbox

$fldarry = new-object EWSUtil.EWS.BaseFolderIdType[] 1
$fldarry[0] = $dTypeFld
$msgList = $ewc.FindUnread($fldarry, $null, $null, "")
if ($msgList.Count -ne 0){
    "Inbox:" + $msgList[0].Subject.ToString()
}

Sie können daher die Beschreibung in eine DLL "einpacken", so dass auch andere Umgebungen eine elegante Unterstützung bei der Entwicklung erlauben.

Visual Studio und Webservices

Natürlich können Visual Studio 2005 und 2008 ganz einfach Webservices einbinden. Über das Projektmenü" wird ein Assistent zum einbinden eines Webservice gestartet, der dann eine "Hilfsklasse" erstellt, die in der späteren Entwicklung einfach genutzt werden kann.

VS 2005 Webservice Assistent

Mit Visual Studio 2008 gibt es eine "Service Referenz"

VS2008 Service reference

Danach können Sie in Visual Studio die Webservices wie jede andere Klasse verwenden

Weitere Links

Hier nur eine kleine Auswahl von Links. Die MSDN-Seite ist sicher die beste Quelle.

Keywords: Webservice Code Programmieren