Sunsetless.Ews.NETStandard
1.2.1
See the version list below for details.
dotnet add package Sunsetless.Ews.NETStandard --version 1.2.1
NuGet\Install-Package Sunsetless.Ews.NETStandard -Version 1.2.1
<PackageReference Include="Sunsetless.Ews.NETStandard" Version="1.2.1" />
<PackageVersion Include="Sunsetless.Ews.NETStandard" Version="1.2.1" />
<PackageReference Include="Sunsetless.Ews.NETStandard" />
paket add Sunsetless.Ews.NETStandard --version 1.2.1
#r "nuget: Sunsetless.Ews.NETStandard, 1.2.1"
#:package Sunsetless.Ews.NETStandard@1.2.1
#addin nuget:?package=Sunsetless.Ews.NETStandard&version=1.2.1
#tool nuget:?package=Sunsetless.Ews.NETStandard&version=1.2.1
Sunsetless EWS for the .NET Standard port
Keep your async EWS Managed API code and run it on Microsoft Graph.
Microsoft is retiring Exchange Web Services (EWS) in Exchange Online: it is switched off by default from October 1, 2026 and retired on April 1, 2027. This package is for applications built on the community .NET Standard port of the EWS Managed API, Microsoft.Exchange.WebServices.NETStandard 1.1.x, with its async API (await service.FindItems(...)). It keeps the port's namespaces, types, method signatures and assembly name. Inside your application it translates calls to Exchange Online into Microsoft Graph calls. Calls to on-premises Exchange keep using EWS, so hybrid setups keep working.
For applications on the original Microsoft package Microsoft.Exchange.WebServices 2.2 (synchronous API), use Sunsetless.Ews instead.
Sunsetless is independent: not affiliated with, endorsed by or sponsored by Microsoft.
Install
Replace the port's package with this one and rebuild your application. Your code compiles unchanged.
dotnet remove package Microsoft.Exchange.WebServices.NETStandard
dotnet add package Sunsetless.Ews.NETStandard
Runs on .NET Framework 4.6.2 or later and on .NET 8, 9 and 10 (the package targets .NET Standard 2.0 and .NET Framework 4.6.2).
The assembly keeps the port's name, Microsoft.Exchange.WebServices.NETStandard.dll, so libraries compiled against the port use this one too. When such a library brings the port's package along, the build keeps this package's file, which has the higher assembly version.
Differences from the port
FileAttachment.Load(Stream)andFileAttachment.Load(string)wait for the content before they return. In the port they return before the content is written.ExchangeService.Timeoutends a call to Exchange Online that takes longer, withServiceRequestException("The operation has timed out").- The 2.0.0 beta versions of the port (with
CancellationTokenparameters) are not covered.
.NET Framework: binding redirects
On .NET Framework the package's dependencies (System.Text.Json, Microsoft.Identity.Client) need assembly binding redirects in the application's config file. Set <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> in the application's project and the build writes them to YourApp.exe.config. A web application reads them from web.config, which the build does not change: add the redirects there by hand.
A missing redirect shows as Could not load file or assembly 'System.Memory, ...'. The located assembly's manifest definition does not match the assembly reference.
Configure
Nothing changes in your code. The library calls Microsoft Graph as an app registration in your Microsoft Entra tenant, so it needs that app's ID and a way to sign in as it. Set four environment variables for the process:
| Variable | Meaning |
|---|---|
SUNSETLESS_TENANT_ID |
Your Microsoft Entra tenant ID |
SUNSETLESS_CLIENT_ID |
The application (client) ID of the app registration |
SUNSETLESS_CLIENT_SECRET |
A client secret of the app registration |
SUNSETLESS_LICENSE_KEY |
Your license key or trial key |
Certificate instead of a client secret
Microsoft recommends a certificate for production. Leave SUNSETLESS_CLIENT_SECRET out and set one of these:
| Variable | Meaning |
|---|---|
SUNSETLESS_CERT_THUMBPRINT |
Thumbprint of the app's certificate in the Windows certificate store (CurrentUser\My or LocalMachine\My) |
SUNSETLESS_CERT_PATH, SUNSETLESS_CERT_PASSWORD |
A .pfx file with the app's certificate, and its password |
Optional settings
| Variable | Meaning |
|---|---|
SUNSETLESS_DEFAULT_MAILBOX |
The mailbox for calls that set no ImpersonatedUserId |
SUNSETLESS_BRIDGED_HOSTS |
The EWS hosts routed to Graph; default outlook.office365.com,outlook.office.com |
SUNSETLESS_DISABLED |
1 switches the translation off; the package then works like the original library |
SUNSETLESS_AUTODISCOVER |
passthrough sends Autodiscover to Exchange instead of answering it from Microsoft Graph |
SUNSETLESS_SCAN_LIMIT |
The largest folder (in items) in which the library itself evaluates filters, sort orders and query strings Microsoft Graph cannot; default 20000. A larger folder answers such a query with a clear error |
Configuration in code
Instead of environment variables, before the first ExchangeService call:
Sunsetless.Ews.SunsetlessEws.Configure(new Sunsetless.Ews.Core.SunsetlessEwsOptions
{
TenantId = "...",
ClientId = "...",
ClientSecret = "...", // or CertificateThumbprint, or CertificatePath and CertificatePassword
LicenseKey = "...",
});
Many tenants in one process
A service that works for several Microsoft 365 tenants, such as a hosted product with many customers, configures each ExchangeService with the values of its tenant. The call replaces the process-wide configuration for that service only:
var service = new ExchangeService(ExchangeVersion.Exchange2013_SP1) { Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx") };
Sunsetless.Ews.SunsetlessEws.Configure(service, new Sunsetless.Ews.Core.SunsetlessEwsOptions
{
TenantId = customer.TenantId,
ClientId = "...",
CertificateThumbprint = "...",
});
Services with the same options share one Microsoft Graph sign-in and token cache, so creating a service per request is fine. Changing the options object afterwards does not affect a configured service. Without LicenseKey the options use the process-wide key or SUNSETLESS_LICENSE_KEY; an ISV key is not tied to a tenant, so one key serves every customer.
Permissions
The app registration needs Microsoft Graph application permissions for what your code does:
| Permission | For |
|---|---|
Mail.ReadWrite, Mail.Send |
mail, mail folders, search folders, conversations, sync and notifications |
Calendars.ReadWrite |
calendars, meetings, availability, delegates |
Contacts.ReadWrite (Contacts.Read to only read) |
contacts, contact pictures, contacts folders, FindPeople in a contacts folder |
Tasks.ReadWrite.All |
tasks (Microsoft To Do) |
MailboxSettings.ReadWrite |
out-of-office settings, inbox rules, delegates' meeting requests, the CategoryList and WorkHours user configurations |
User.Read.All, Group.Read.All |
ResolveNames, ExpandDL, FindPeople in the directory, user photos, GetPasswordExpirationDate |
Place.Read.All |
room lists |
MailboxFolder.Read.All |
folders of every kind (calendar, contacts, tasks, notes, journal) when listing from the mailbox root; the Notes, Journal and Root folders and their items (sticky notes, journal entries) |
MailboxItem.Read.All |
contact groups (read); task properties To Do does not carry (size, percent complete, work and billing fields, extended properties); contacts, calendar items and tasks that lie in Deleted Items or Recoverable Items |
MailboxItem.ImportExport.All |
what Microsoft Graph has no call of its own for, done through the mailbox export and import: MoveItem and CopyItem of contacts, tasks and calendar items; posts (PostItem, PostReplyItem); contact groups (create, change, delete); meetings saved, changed, moved or deleted with SendToNone; task fields To Do does not keep (any percent complete, work, mileage, billing, companies, sensitivity, extended properties, regenerating recurrence); file attachments of contacts; attached messages that carry attachments of their own or are given as MIME; an .eml imported as a received message; SuppressReadReceipts; SoftDelete of contacts, tasks and appointments; ICalUid in UpdateItem |
Domain.Read.All |
optional: Autodiscover GetDomainSettings and GetAppMarketplaceUrl |
Without the last four the rest works; the library then lists mail folders only from the root, reads tasks from To Do alone, shows no contact groups, and answers the Notes and Journal folders and the operations listed for MailboxItem.ImportExport.All with an error that names the missing permission.
Autodiscover (AutodiscoverUrl, GetUserSettings, GetDomainSettings) is answered from Microsoft Graph, because Exchange Online refuses app-only tokens there. SUNSETLESS_AUTODISCOVER=passthrough sends it to Exchange instead.
Limit the mailboxes the app can open with RBAC for Applications in Exchange Online.
License
Sunsetless EWS is commercial software. You get a license key at https://sunsetless.com/pricing, or a free trial key for testing at https://sunsetless.com/trial. Without a valid key the package does not call Microsoft Graph, and calls fail with ErrorInvalidLicense. The key is checked offline, and the package sends no telemetry. The terms are at https://sunsetless.com/terms.
What is covered
The supported operations, what was verified against live Exchange Online, and the known differences between EWS and Graph are listed at https://sunsetless.com/compatibility. To check an application, open its EWS usage report in the checker at https://sunsetless.com/coverage-check. The report stays in your browser. Without the report, the free tool ews-scan (https://github.com/sunset-less/ews-scan) lists the EWS operations in the compiled application: dotnet tool install --global Sunsetless.EwsScan.
This version has no preview operations. Operations added in later versions before they are verified against live Exchange Online will be off by default and listed on the compatibility page; SUNSETLESS_PREVIEW_FEATURES=true will switch them on.
Support
contact@sunsetless.com
Third-party code
Built on the source code of the .NET Standard port of the EWS Managed API (https://github.com/sherlock1982/ews-managed-api), Copyright (c) Microsoft Corporation and contributors, MIT License. Its license text is in licenses/ews-managed-api-license.txt in this package.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- Microsoft.Identity.Client (>= 4.90.1)
- System.Text.Json (>= 10.0.12)
-
.NETStandard 2.0
- Microsoft.Identity.Client (>= 4.90.1)
- System.Security.Cryptography.Xml (>= 10.0.12)
- System.Text.Json (>= 10.0.12)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Fixes: Autodiscover (AutodiscoverUrl, GetUserSettings, GetDomainSettings) is answered from Microsoft Graph, also with OAuthCredentials, where the port threw NotImplementedException; Autodiscover for an on-premises mailbox in a hybrid deployment reaches the on-premises Autodiscover; Autodiscover is behind the license check like every other request; the Microsoft Graph token goes only over https to the Graph host; a SyncState whose links lead outside the caller's mailbox is refused with ErrorInvalidSyncStateData. Supported operations, verification against live Exchange Online and known differences: https://sunsetless.com/compatibility