EWS クライアント アプリケーションの概要
Exchange Web サービス (EWS) を使用して、Exchange の初めてのアプリケーションを作成します。
EWS は、Office 365または Exchange オンプレミス メールボックスの一部としてExchange Online、Exchange Onlineに格納されているほぼすべての情報にアプリケーションがアクセスするために使用できる包括的なサービスです。 EWS では、標準の Web プロトコルを使用して Exchange サーバーへのアクセスを提供します。 EWS マネージ API などのライブラリは、EWS 操作をラップしてオブジェクト指向のインターフェイスを提供します。 この記事の例を実行すると、EWS でできることの基本的な理解が得つかります。
EWS 要求と応答では SOAP プロトコルが使用されるため、任意のオペレーティング システムまたは言語から EWS 操作を呼び出すことができます。 この記事の例では、C# を使用して記述し、.NET Framework HttpWebRequest オブジェクトと HttpWebResponse オブジェクトを使用します。ただし、コードの重要な部分は、EWS 要求を行うために使用される XML と、サーバーから返される XML 応答です。 コード例では、XML トランザクションを強調し、XML を処理しません。
注:
2022 年 10 月より、Exchange Online for EWS で基本認証を使用する機能が削除されます Exchange Online での基本認証の廃止。 代わりに OAuth 認証を使用する必要があります。 OAuth を使用して EWS アプリケーションを認証する
Exchange サーバーの準備
Exchange メールボックス アカウントを既に所有している場合は、この手順を省略してもかまいません。 それ以外の場合は、次のいずれかの方法で、初めての EWS アプリケーション用の Exchange メールボックスをセットアップします。
Office 365開発者向けサイトを取得する (推奨)。 最も簡単に Exchange メールボックスを入手する方法です。
Exchange Server をダウンロードする。
Exchange サーバーから電子メールを送受信できることを確認したら、開発環境をセットアップするための準備が完了します。 Outlook Web App を使用して、電子メールが送信できることを確認します。
また、サーバーの EWS エンドポイントの URL を確認することも必要になります。 実稼働アプリケーションでは、自動検出を使用して EWS の URL を判断します。 この記事の例では、Office 365 EWS エンドポイント の URL https://outlook.office365.com/EWS/Exchange.asmx
を使用します。 「次の手順」のセクションには、自動検出に関する詳細へのリンクが掲載されています (必要になったら参照してください)。
アプリケーションのテストに、既定の自己署名証明書がある Exchange サーバーを使用する場合は、自分の組織のセキュリティ要件に適合する証明書の検証メソッドを作成する必要があります。
開発環境のセットアップ
初めての EWS アプリケーションの作成に使用するツールは、どのオペレーティング システムと言語を使用するかによって決まりますが、大部分は好みの問題になります。 この記事の C# の例に沿って進めようとしている場合は、次のものが必要になります。
- .NET Framework 4.0 をサポートしているバージョンの Visual Studio。
- 開発マシンから Exchange サーバーへの接続に使用できるインターネット接続。 IP アドレスではなく DNS 名で Exchange サーバーに接続する Outlook Web App を使用できる場合は、セットアップが完了しています。
初めての EWS アプリケーションの作成
これから作成する EWS アプリケーションでは、EWS を使用する際の一般的な 2 つのシナリオについて示します。
- Exchange メールボックスから情報を取得して、その情報をユーザーに表示する。
- 電子メールの送信などのアクションを実行して、そのアクションが成功したかどうかを確認するために応答を調べる。
それでは始めましょう。
ソリューションのセットアップ
まず、Visual Studio を使用して、新しいコンソール アプリケーション ソリューションを作成します。 ソリューションの準備ができたら、Tracing.cs という名前の新しいオブジェクトを作成します。 このオブジェクトを使用して、コンソールとログ ファイルの両方に情報を書き込み、コードの実行後に結果を確認できるようにします。 Tracing.cs ファイルに、次のコードを貼り付けます。
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();
}
}
}
次に、Program.cs ファイルを開きます。 この例のコードの残りの部分は、このファイルに記述することになります。
まず、プログラムの外郭をセットアップします。 プログラムでは、次を実行します。
- ログ ファイルを作成して、後からの調査のために要求と応答をディスクに書き込めるようにします。
- アクセスするアカウントの電子メール アドレスとパスワードを取得します。
- 簡単なメソッドを呼び出します。
Program.cs の Main
メソッドを次のコードに置き換えます。
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)
{
}
最後に、静的メソッドを追加する GetPasswordFromConsole
必要があります。 このメソッドは、コンソールで入力されたパスワードを含む SecureString オブジェクトを返します。
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;
}
受信トレイにある新しいメッセージ数の取得
EWS アプリケーションの一般的な操作とは、電子メール メッセージ、予定、会議、およびそれらを格納するフォルダーに関する情報を取得することです。 この例では、アカウントの受信トレイ内にあるメッセージ数を取得して、合計メッセージ数と未読メッセージ数を表示します。 ここでは、EWS アプリケーションにとって一般的な次のアクションについて示します
- Exchange サーバーへの EWS の要求。
- 要求した情報に対して返される XML 応答の解析。
- 一般的な例外とエラー メッセージの処理。
main メソッドの後に ShowNumberOfMessagesInInbox
スタブアウトされたメソッドに次のコードを追加します。 アプリケーションを実行すると、アカウントの受信トレイ内にあるメッセージの数と、受信トレイ内で未読のメッセージ数が出力されます。 アプリケーションの実行後に、GetStartedWithEWS.log ファイルを開くと、Exchange サーバーに送信された XML 要求と、サーバーから返された応答を確認できます
/// 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=\"http://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=\"http://schemas.microsoft.com/exchange/services/2006/messages\"\n" +
" xmlns:t=\"http://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
("{http://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
("{http://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
("{http://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
("{http://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
("{http://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);
}
電子メール メッセージの送信
もう 1 つの EWS アプリケーションの一般的な操作は、電子メール メッセージや会議出席依頼の送信です。 この例では、電子メール メッセージを作成して、以前に入力されたユーザーの資格情報を使用して送信します。 ここでは、一般的な EWS アプリケーションの 3 つのタスクを例示しています。
電子メールの作成と送信。
返された XML 応答の解析 (電子メールが正しく送信されたかどうかを判断します)。
一般的な例外とエラー メッセージの処理。
main メソッドの後でスタブアウトされていた SendTestEmail メソッドに、次のコードを追加します。 アプリケーションの実行後に、GetStartedWithEWS.log ファイルを開くと、Exchange サーバーに送信された XML 要求と、サーバーから返された応答を確認できます
var createItemSOAPRequest =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" +
" xmlns:m=\"http://schemas.microsoft.com/exchange/services/2006/messages\" \n" +
" xmlns:t=\"http://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
("{http://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);
}
次の手順
最初の EWS アプリケーションを作成したので、EWS を使用する他の方法を見つけ出す準備ができました。 作業を開始するためのアイデアを次に示します。
ユーザーの電子メール アドレスに応じて適切な Exchange サーバーに接続するように、アプリケーションに自動検出を実装する。 「Exchange 2013: Get user settings with Autodiscover」サンプルも参照してください。
EWS の詳細について、EWS のリファレンスで調べる。
使用可能な操作について、EWS の操作で確認する。
EWS エディタを使用して、サーバーとやり取りされる SOAP トラフィックを確認する。
カスタムアプリケーションに問題が発生したときには、質問やコメントをフォーラムに投稿してみてください (最初の投稿は忘れずにお読みください)。