Erste Schritte mit EWS-Clientanwendungen

Erstellen Sie Ihre erste Anwendung mithilfe von Exchange-Webdienste (EWS) in Exchange.

EWS ist ein umfassender Dienst, mit dem Ihre Anwendungen auf fast alle Informationen zugreifen können, die in einem Exchange Online gespeichert sind, Exchange Online als Teil Office 365 oder lokalen Exchange-Postfachs gespeichert sind. EWS verwendet Standardwebprotokolle, um zugriff auf einen Exchange-Server zu ermöglichen. Bibliotheken wie die verwaltete EWS-API umschließen die EWS-Vorgänge, um eine objektorientierte Schnittstelle bereitzustellen. Nachdem Sie die Beispiele in diesem Artikel ausgeführt haben, haben Sie ein grundlegendes Verständnis dafür, was Sie mit EWS tun können.

Sie können EWS-Vorgänge unter jedem Betriebssystem und in jeder Sprache aufrufen, da die EWS-Anforderungen und -Antworten das SOAP-Protokoll verwenden. Die Beispiele in diesem Artikel sind in C# geschrieben und verwenden die .NET Framework-Objekte HttpWebRequest und HttpWebResponse ; die wichtigen Teile des Codes sind jedoch der XML-Code zum Durchführen der EWS-Anforderung und die vom Server zurückgegebene XML-Antwort. Die Codebeispiele konzentrieren sich auf die XML-Transaktionen, und nicht auf die Verarbeitung des XML-Codes.

Hinweis

Die Möglichkeit der Standardauthentifizierung in Exchange Online für EWS, wird ab Oktober 2022 eingestellt. Einstellung der Standardauthentifizierung in Exchange Online. Sie sollten stattdessen die OAuth-Authentifizierung verwenden. Authentifizieren einer EWS-Anwendung mit OAuth

Sie benötigen einen Exchange-Server

Wenn Sie bereits über ein Exchange-Postfachkonto verfügen, können Sie diesen Schritt überspringen. Andernfalls können Sie mit einer der folgenden Methoden ein Exchange-Postfach für Ihre erste EWS-Anwendung einrichten:

Nachdem Sie sichergestellt haben, dass Sie E-Mails von Ihrem Exchange-Server senden und empfangen können, sind Sie zum Einrichten der Entwicklungsumgebung bereit. Sie können Outlook Web App verwenden, um zu überprüfen, ob Sie E-Mails senden können.

Sie müssen außerdem die URL des EWS-Endpunkts für Ihren Server kennen. Verwenden Sie in einer Produktionsumgebung die AutoErmittlung zur Ermittlung der EWS-URL. Die Beispiele in diesem Artikel verwenden die Office 365-EWS-Endpunkt-URL "https://outlook.office365.com/EWS/Exchange.asmx". Im Abschnitt Nächste Schritte finden Sie Links zu weiteren Informationen über die AutoErmittlung, wenn Sie bereit sind.

Wenn Sie Ihre Anwendung mit einem Exchange-Server testen, der über das selbstsignierte Standardzertifikat verfügt, müssen Sie eine Zertifikatüberprüfungsmethode erstellen, die die Sicherheitsanforderungen Ihrer Organisation erfüllt.

Einrichten der Entwicklungsumgebung

Die Tools, die Sie zum Erstellen Ihrer ersten EWS-Anwendung verwenden, hängen vom verwendeten Betriebssystem und der verwendeten Sprache ab und sind hauptsächlich Geschmackssache. Wenn Sie die C#-Beispiele in diesem Artikel befolgen möchten, benötigen Sie Folgendes:

  • Eine beliebige Version von Visual Studio, die .NET Framework 4.0 unterstützt
  • Eine Internetverbindung, über die der Entwicklungscomputer den Exchange-Server kontaktieren kann. Wenn Sie Outlook Web App verwenden und die Verbindung mit dem Exchange-Server über einen DNS-Namen statt über eine IP-Adresse herstellen, müssen Sie keine weiteren Schritte ausführen.

Erstellen der ersten EWS-Anwendung

Die EWS-Anwendung, die Sie erstellen werden, zeigt zwei typische Szenarien für die Verwendung von EWS:

  1. Abrufen von Informationen aus einem Exchange-Postfach und Anzeigen dieser Informationen für den Benutzer
  2. Durchführen einer Aktion, z. B. Senden einer E-Mail, und Überprüfen der Antwort, um festzustellen, ob der Vorgang erfolgreich war

Lassen Sie uns beginnen.

Einrichten der Lösung

Erstellen Sie zuerst eine neue Konsolenanwendungslösung unter Verwendung von Visual Studio. Wenn die Lösung bereit ist, erstellen Sie ein neues Objekt namens "Tracing.cs". Verwenden Sie dieses Objekt, um Informationen in die Konsole und in eine Protokolldatei zu schreiben, damit Sie die Ergebnisse überprüfen können, nachdem Sie den Code ausgeführt haben. Fügen Sie den folgenden Code in die Datei "Tracing.cs" ein.

using System;
using System.IO;
namespace Microsoft.Exchange.Samples.EWS
{
  class Tracing
  {
    private static TextWriter logFileWriter = null;
    public static void OpenLog(string fileName)
    {
      logFileWriter = new StreamWriter(fileName);
    }
    public static void Write(string format, params object[] args)
    {
      Console.Write(format, args);
      if (logFileWriter != null)
      {
        logFileWriter.Write(format, args);
      }
    }
    public static void WriteLine(string format, params object[] args)
    {
      Console.WriteLine(format, args);
      if (logFileWriter != null)
      {
        logFileWriter.WriteLine(format, args);
      }
    }
    public static void CloseLog()
    {
      logFileWriter.Flush();
      logFileWriter.Close();
    }
  }
}

Öffnen Sie dann die Datei "Program.cs". Fügen Sie den restlichen Code für das Beispiel in diese Datei ein.

Richten Sie zuerst die Shell des Programms ein. Das Programm führt folgende Aufgaben aus:

  1. Erstellen einer Protokolldatei, sodass die Anforderung und die Antwort für spätere Untersuchungen auf Datenträger geschrieben werden können
  2. Abrufen der E-Mail-Adresse und des Kennworts des Kontos, auf das Sie zugreifen
  3. Aufrufen der Beispielmethoden

Ersetzen Sie die Main-Methode in der Datei "Program.cs" durch den folgenden Code.

    static void Main(string[] args)
    {
      // Start tracing to console and a log file.
      Tracing.OpenLog("./GetStartedWithEWS.log");
      Tracing.WriteLine("EWS sample application started.");
      var isValidEmailAddress = false;
      Console.Write("Enter an email address: ");
      var emailAddress = Console.ReadLine();
      
        isValidEmailAddress = (emailAddress.Contains("@") && emailAddress.Contains("."));
      if (!isValidEmailAddress)
      {
        Tracing.WriteLine("Email address " + emailAddress + " is not a valid SMTP address. Closing program.");
        return;
      }
      SecureString password = GetPasswordFromConsole();
      if (password.Length == 0)
      {
        Tracing.WriteLine("Password empty, closing program.");
      }
      NetworkCredential userCredentials = new NetworkCredential(emailAddress, password);
      // These are the sample methods that demonstrate using EWS.
      // ShowNumberOfMessagesInInbox(userCredentials);
      // SendTestEmail(userCredentials);
     
      Tracing.WriteLine("EWS sample application ends.");
      Tracing.CloseLog();
      Console.WriteLine("Press enter to exit: ");
      Console.ReadLine();
    }
    // These method stubs will be filled in later.
    private static void ShowNumberOfMessagesInInbox(NetworkCredential userCredentials)
    {
    }
    private static void SendTestEmail(NetworkCredential userCredentials)
    {
    }

Das letzte, was Sie tun müssen, ist das Hinzufügen der GetPasswordFromConsole statischen Methode. Diese Methode gibt ein SecureString -Objekt mit einem Kennwort zurück, das an der Konsole eingegeben wurde.

    private static SecureString GetPasswordFromConsole()
    {
      SecureString password = new SecureString();
      bool readingPassword = true;
      Console.Write("Enter password: ");
      while (readingPassword)
      {
        ConsoleKeyInfo userInput = Console.ReadKey(true);
        switch (userInput.Key)
        {
          case (ConsoleKey.Enter):
            readingPassword = false;
            break;
          case (ConsoleKey.Escape):
            password.Clear();
            readingPassword = false;
            break;
          case (ConsoleKey.Backspace):
            if (password.Length > 0)
            {
              password.RemoveAt(password.Length - 1);
              Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
              Console.Write(" ");
              Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
            }
            break;
          default:
            if (userInput.KeyChar != 0)
            {
              password.AppendChar(userInput.KeyChar);
              Console.Write("*");
            }
            break;
        }
      }
      Console.WriteLine();
      password.MakeReadOnly();
      return password;
    }

Abrufen der Anzahl neuer Nachrichten im Posteingang

Ein gängiger Vorgang in einer EWS-Anwendung ist das Abrufen von Informationen über E-Mail-Nachrichten, Termine, Besprechungen und die Ordner, in denen diese Elemente gespeichert sind. In diesem Beispiel wird die Anzahl der Nachrichten im Posteingang eines Kontos abgerufen; außerdem werden die Gesamtanzahl der Nachrichten und die Anzahl der ungelesenen Nachrichten angezeigt. Das Beispiel veranschaulicht die folgenden gängigen Aktionen für EWS-Anwendungen:

  • Durchführen einer EWS-Anforderung an den Exchange-Server
  • Analysieren der zurückgegebenen XML-Antwort im Hinblick auf die angeforderten Informationen
  • Behandeln von allgemeinen Ausnahmen und Fehlermeldungen

Fügen Sie der Methode, die nach der ShowNumberOfMessagesInInbox main-Methode gestubbt wurde, den folgenden Code hinzu. Wenn Sie die Anwendung ausführen, werden die Anzahl der Nachrichten im Posteingang des Kontos und die Anzahl der ungelesenen Nachrichten im Posteingang ausgegeben. Nachdem Sie die Anwendung ausgeführt haben, können Sie die Datei "GetStartedWithEWS.log" öffnen, um die XML-Anforderung anzuzeigen, die an den Exchange-Server gesendet wurde, sowie die vom Server zurückgegebene Antwort.

      /// This is the XML request that is sent to the Exchange server.
      var getFolderSOAPRequest =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<soap:Envelope xmlns:soap=\"https://schemas.xmlsoap.org/soap/envelope/\"\n" +
"   xmlns:t=\"https://schemas.microsoft.com/exchange/services/2006/types\">\n" +
"<soap:Header>\n" +
"    <t:RequestServerVersion Version=\"Exchange2007_SP1\" />\n" +
"  </soap:Header>\n" +
"  <soap:Body>\n" +
"    <GetFolder xmlns=\"https://schemas.microsoft.com/exchange/services/2006/messages\"\n" +
"               xmlns:t=\"https://schemas.microsoft.com/exchange/services/2006/types\">\n" +
"      <FolderShape>\n" +
"        <t:BaseShape>Default</t:BaseShape>\n" +
"      </FolderShape>\n" +
"      <FolderIds>\n" +
"        <t:DistinguishedFolderId Id=\"inbox\"/>\n" +
"      </FolderIds>\n" +
"    </GetFolder>\n" +
"  </soap:Body>\n" +
"</soap:Envelope>\n";
      // Write the get folder operation request to the console and log file.
      Tracing.WriteLine("Get folder operation request:");
      Tracing.WriteLine(getFolderSOAPRequest);
      var getFolderRequest = WebRequest.CreateHttp(Office365WebServicesURL);
      getFolderRequest.AllowAutoRedirect = false;
      getFolderRequest.Credentials = userCredentials;
      getFolderRequest.Method = "POST";
      getFolderRequest.ContentType = "text/xml";
      var requestWriter = new StreamWriter(getFolderRequest.GetRequestStream());
      requestWriter.Write(getFolderSOAPRequest);
      requestWriter.Close();
      try
      {
        var getFolderResponse = (HttpWebResponse)(getFolderRequest.GetResponse());
        if (getFolderResponse.StatusCode == HttpStatusCode.OK)
        {
          var responseStream = getFolderResponse.GetResponseStream();
          XElement responseEnvelope = XElement.Load(responseStream);
          if (responseEnvelope != null)
          {
            // Write the response to the console and log file.
            Tracing.WriteLine("Response:");
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(stringBuilder, settings);
            responseEnvelope.Save(writer);
            writer.Close();
            Tracing.WriteLine(stringBuilder.ToString());
            // Check the response for error codes. If there is an error, throw an application exception.
            IEnumerable<XElement> errorCodes = from errorCode in responseEnvelope.Descendants
                                               ("{https://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode")
                                               select errorCode;
            foreach (var errorCode in errorCodes)
            {
              if (errorCode.Value != "NoError")
              {
                switch (errorCode.Parent.Name.LocalName.ToString())
                {
                  case "Response":
                    string responseError = "Response-level error getting inbox information:\n" + errorCode.Value;
                    throw new ApplicationException(responseError);
                  case "UserResponse":
                    string userError = "User-level error getting inbox information:\n" + errorCode.Value;
                    throw new ApplicationException(userError);
                }
              }
            }
            // Process the response.
            IEnumerable<XElement> folders = from folderElement in
                                              responseEnvelope.Descendants
                                              ("{https://schemas.microsoft.com/exchange/services/2006/messages}Folders")
                                            select folderElement;
            foreach (var folder in folders)
            {
              Tracing.Write("Folder name:     ");
              var folderName = from folderElement in
                                 folder.Descendants
                                 ("{https://schemas.microsoft.com/exchange/services/2006/types}DisplayName")
                               select folderElement.Value;
              Tracing.WriteLine(folderName.ElementAt(0));
              Tracing.Write("Total messages:  ");
              var totalCount = from folderElement in
                                 folder.Descendants
                                   ("{https://schemas.microsoft.com/exchange/services/2006/types}TotalCount")
                               select folderElement.Value;
              Tracing.WriteLine(totalCount.ElementAt(0));
              Tracing.Write("Unread messages: ");
              var unreadCount = from folderElement in
                                 folder.Descendants
                                   ("{https://schemas.microsoft.com/exchange/services/2006/types}UnreadCount")
                               select folderElement.Value;
              Tracing.WriteLine(unreadCount.ElementAt(0));
            }
          }
        }
      }
      catch (WebException ex)
      {
        Tracing.WriteLine("Caught Web exception:");
        Tracing.WriteLine(ex.Message);
      }
      catch (ApplicationException ex)
      {
        Tracing.WriteLine("Caught application exception:");
        Tracing.WriteLine(ex.Message);
      }

Senden einer E-Mail-Nachricht

Ein weiterer gängiger Vorgang für eine EWS-Anwendung ist das Senden von E-Mail-Nachrichten oder Besprechungsanfragen. Dieses Beispiel erstellt und sendet eine E-Mail-Nachricht unter Verwendung der zuvor eingegebenen Anmeldeinformationen. Die folgenden gängigen EWS-Anwendungsaufgaben werden veranschaulicht:

  • Erstellen und Senden einer E-Mail

  • Analysieren der zurückgegebenen XML-Antwort, um zu bestimmen, ob die E-Mail ordnungsgemäß gesendet wurde

  • Behandeln von allgemeinen Ausnahmen und Fehlermeldungen

Fügen Sie der SendTestEmail-Methode, die als Stub nach der main-Methode vorliegt, den folgenden Code hinzu. Nachdem Sie die Anwendung ausgeführt haben, können Sie die Datei "GetStartedWithEWS.log" öffnen, um die XML-Anforderung anzuzeigen, die an den Exchange-Server gesendet wurde, sowie die vom Server zurückgegebene Antwort.

var createItemSOAPRequest =
      "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
      "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" +
      "               xmlns:m=\"https://schemas.microsoft.com/exchange/services/2006/messages\" \n" +
      "               xmlns:t=\"https://schemas.microsoft.com/exchange/services/2006/types\" \n" +
      "               xmlns:soap=\"https://schemas.xmlsoap.org/soap/envelope/\">\n" +
      "  <soap:Header>\n" +
      "    <t:RequestServerVersion Version=\"Exchange2007_SP1\" />\n" +
      "  </soap:Header>\n" +
      "  <soap:Body>\n" +
      "    <m:CreateItem MessageDisposition=\"SendAndSaveCopy\">\n" +
      "      <m:SavedItemFolderId>\n" +
      "        <t:DistinguishedFolderId Id=\"sentitems\" />\n" +
      "      </m:SavedItemFolderId>\n" +
      "      <m:Items>\n" +
      "        <t:Message>\n" +
      "          <t:Subject>Company Soccer Team</t:Subject>\n" +
      "          <t:Body BodyType=\"HTML\">Are you interested in joining?</t:Body>\n" +
      "          <t:ToRecipients>\n" +
      "            <t:Mailbox>\n" +
      "              <t:EmailAddress>sadie@contoso.com</t:EmailAddress>\n" +
      "              </t:Mailbox>\n" +
      "          </t:ToRecipients>\n" +
      "        </t:Message>\n" +
      "      </m:Items>\n" +
      "    </m:CreateItem>\n" +
      "  </soap:Body>\n" +
      "</soap:Envelope>\n";
      // Write the create item operation request to the console and log file.
      Tracing.WriteLine("Get folder operation request:");
      Tracing.WriteLine(createItemSOAPRequest);
      var getFolderRequest = WebRequest.CreateHttp(Office365WebServicesURL);
      getFolderRequest.AllowAutoRedirect = false;
      getFolderRequest.Credentials = userCredentials;
      getFolderRequest.Method = "POST";
      getFolderRequest.ContentType = "text/xml";
      var requestWriter = new StreamWriter(getFolderRequest.GetRequestStream());
      requestWriter.Write(createItemSOAPRequest);
      requestWriter.Close();
      try
      {
        var getFolderResponse = (HttpWebResponse)(getFolderRequest.GetResponse());
        if (getFolderResponse.StatusCode == HttpStatusCode.OK)
        {
          var responseStream = getFolderResponse.GetResponseStream();
          XElement responseEnvelope = XElement.Load(responseStream);
          if (responseEnvelope != null)
          {
            // Write the response to the console and log file.
            Tracing.WriteLine("Response:");
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            XmlWriter writer = XmlWriter.Create(stringBuilder, settings);
            responseEnvelope.Save(writer);
            writer.Close();
            Tracing.WriteLine(stringBuilder.ToString());
            // Check the response for error codes. If there is an error, throw an application exception.
            IEnumerable<XElement> errorCodes = from errorCode in responseEnvelope.Descendants
                                               ("{https://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode")
                                               select errorCode;
            foreach (var errorCode in errorCodes)
            {
              if (errorCode.Value != "NoError")
              {
                switch (errorCode.Parent.Name.LocalName.ToString())
                {
                  case "Response":
                    string responseError = "Response-level error getting inbox information:\n" + errorCode.Value;
                    throw new ApplicationException(responseError);
                  case "UserResponse":
                    string userError = "User-level error getting inbox information:\n" + errorCode.Value;
                    throw new ApplicationException(userError);
                }
              }
            }
            Tracing.WriteLine("Message sent successfully.");
          }
        }
      }
      catch (WebException ex)
      {
        Tracing.WriteLine("Caught Web exception:");
        Tracing.WriteLine(ex.Message);
      }
      catch (ApplicationException ex)
      {
        Tracing.WriteLine("Caught application exception:");
        Tracing.WriteLine(ex.Message);
      }

Nächste Schritte

Nachdem Sie Ihre erste EWS-Anwendung geschrieben haben, können Sie weitere Möglichkeiten zum Verwenden von EWS erkunden. Hier sind einige Ideen für die ersten Schritte:

Falls Probleme mit der Anwendung auftreten, veröffentlichen Sie eine Frage oder einen Kommentar im Forum (und vergessen Sie nicht, den ersten Beitrag zu lesen).

Siehe auch