Interacting with EWS¶
The following two projects have been tested are known to work well with the Kopano Cloud EWS implementation.
- Python: Exchange Web Services client library
- This library does not support the same auto discovery methods we implement, therefore the server url needs to be specified.
- .NET: Microsoft.Exchange.WebServices.NETStandard
Note
A lot of calls require E4A_ENABLE_EWS_EXPERIMENTAL_OPERATIONS=true to be set as an environment in the container.
Examples¶
With the following example script the out of office settings of a user can be retrieved:
#!/usr/bin/env python
import argparse
import exchangelib
import logging
import os
import pprint
def get_user_oof_settings(autodiscover, url, username, password, smtp_address):
creds = exchangelib.Credentials(username, password)
if False:
# Set version client side, as the automatic version discovery is an extra
# request which we do not support.
version = exchangelib.Version(build=exchangelib.version.EXCHANGE_2007_SP1)
else:
version = None
if autodiscover:
account = exchangelib.Account(
primary_smtp_address=smtp_address, credentials=creds, autodiscover=True, access_type=exchangelib.DELEGATE
)
else:
config = exchangelib.Configuration(service_endpoint=url, credentials=creds, version=version)
account = exchangelib.Account(
primary_smtp_address=smtp_address, config=config, autodiscover=False, access_type=exchangelib.DELEGATE
)
# Fetch OOF settings.
oof_settings = account.oof_settings
return oof_settings
def main():
parser = argparse.ArgumentParser(description="Retrieve OOF settings using Exchange Web Services.")
parser.add_argument("--autodiscover", action="store_true", help="Enable autodiscovery (default: False)")
parser.add_argument(
"--url",
type=str,
default="https://exchange4all.local/EWS/Exchange.asmx",
help="The URL to Exchange.asmx if autodiscover is not used",
)
parser.add_argument("--username", type=str, required=True, help="The username for authentication")
parser.add_argument("--password", type=str, required=True, help="The password for Basic authentication")
parser.add_argument("--smtp-address", type=str, required=True, help="The SMTP address of the mailbox")
args = parser.parse_args()
# Make requests use the system certificates (Linux only).
os.environ["REQUESTS_CA_BUNDLE"] = "/etc/ssl/certs/ca-certificates.crt"
if True:
from exchangelib.util import PrettyXmlHandler
logging.basicConfig(level=logging.DEBUG, handlers=[PrettyXmlHandler()])
try:
oof_settings = get_user_oof_settings(
autodiscover=args.autodiscover,
url=args.url,
username=args.username,
password=args.password,
smtp_address=args.smtp_address,
)
except Exception as e:
print(f"Error: {e}")
exit(1)
finally:
exchangelib.close_connections()
print("Success!\n")
pprint.pp(oof_settings, indent=4)
if __name__ == "__main__":
main()
Example for user .NET:
using System;
using System.CommandLine;
using Microsoft.Exchange.WebServices.Data;
namespace GetUserOofSettings;
class Program
{
static async Task<int> Main(string[] args)
{
var rootCommand = new RootCommand("Simple EWS example to retriefe OOF settings");
var autoDiscoverOption = new Option<bool>(
"--autodiscover",
description: "Enable autodiscovery (default: false) (if set, the --url flag is ignored) (works on Windows only!)"
);
rootCommand.AddGlobalOption(autoDiscoverOption);
var urlOption = new Option<string>(
"--url",
description: "The URL to Exchange.asmx (required if autodiscover is not used)", getDefaultValue: () => "https://exchange4all.local/EWS/Exchange.asmx");
rootCommand.AddGlobalOption(urlOption);
var usernameOption = new Option<string>(
"--username",
description: "The username (for autodiscovery and/or Basic authentication)")
{
IsRequired = true,
};
rootCommand.AddGlobalOption(usernameOption);
var passwordOption = new Option<string>(
"--password",
description: "The password for Basic authentication");
rootCommand.AddGlobalOption(passwordOption);
var accessTokenOption = new Option<string>(
"--access-token",
description: "The acesss token (if set, use Bearer authentication)");
rootCommand.AddGlobalOption(accessTokenOption);
var smtpAddressOption = new Option<string>(
"--smtp-address",
description: "The SMTP address of the mailbox")
{
IsRequired = true
};
rootCommand.AddOption(smtpAddressOption);
int returnCode = 0;
rootCommand.SetHandler(async (bool autodiscover, string url, string username, string password, string accessToken, string smtpAddress) =>
{
returnCode = await DoGetUserOofSettings(autodiscover, url, username, password, accessToken, smtpAddress);
}, autoDiscoverOption, urlOption, usernameOption, passwordOption, accessTokenOption, smtpAddressOption);
await rootCommand.InvokeAsync(args);
return returnCode;
}
public static async Task<int> DoGetUserOofSettings(bool autodiscover, string url, string username, string password, string acessToken, string smtpAddress)
{
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials(username, password);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.UseDefaultCredentials = false;
service.EnableScpLookup = false;
if (autodiscover)
{
// Autodiscovery does not work very good on Linux as the hack in
// https://github.com/sherlock1982/ews-managed-api/blob/a5c23339b30a773dac5b3c740d3df6a1a4c7ac76/Autodiscover/AutodiscoverService.cs#L1547 is not working and fails
// with exception as it lacks a check for url != null. Also for
// any requested server version > Exchange2007_SP1 this also fails
// on linux since the Legacy service is nver tried as the exception
// for DNS srv will be reached first (since we don't support the
// SOAP based autodiscovery)
// See tests/dotnet-example/GetUserOofSettings/GetUserOofSettings.csproj
// how to install a partly fixed version.
await service.AutodiscoverUrl(username, RedirectionUrlValidationCallback);
}
else
{
service.Url = new Uri(url);
}
OofSettings oofsettings = await service.GetUserOofSettings(smtpAddress);
Console.WriteLine(ObjectDumper.Dump(oofsettings, DumpStyle.CSharp));
return 0;
}
private static bool RedirectionUrlValidationCallback(string redirectionUrl)
{
// The default for the validation callback is to reject the URL.
bool result = false;
Uri redirectionUri = new Uri(redirectionUrl);
// Validate the contents of the redirection URL. In this simple validation
// callback, the redirection URL is considered valid if it is using HTTPS
// to encrypt the authentication credentials.
if (redirectionUri.Scheme == "https")
{
result = true;
}
return result;
}
}