Sunsetless.Ews.NETStandard 2.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Sunsetless.Ews.NETStandard --version 2.0.0
                    
NuGet\Install-Package Sunsetless.Ews.NETStandard -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sunsetless.Ews.NETStandard" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sunsetless.Ews.NETStandard" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Sunsetless.Ews.NETStandard" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sunsetless.Ews.NETStandard --version 2.0.0
                    
#r "nuget: Sunsetless.Ews.NETStandard, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sunsetless.Ews.NETStandard@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sunsetless.Ews.NETStandard&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Sunsetless.Ews.NETStandard&version=2.0.0
                    
Install as a Cake Tool

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. From October 10, 2026, a tenant that keeps EWS on (EWSEnabled set to True) has to list the apps allowed to use it in EWSAllowedAppIDs. In the other tenants Microsoft switches EWS off in waves, each announced in the Message Center 7 days ahead. On April 1, 2027 EWS is retired. 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. Unlike the port's, it is strong-named (public key token 1b8c25c6fc94dcf1), so strong-named applications and components can reference it on .NET Framework. On .NET 8, 9 and 10, libraries compiled against the port use this file too; on .NET Framework, rebuild them against this package. 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) and FileAttachment.Load(string) wait for the content before they return. In the port they return before the content is written.
  • ExchangeService.Timeout ends a call to Exchange Online that takes longer, with ServiceRequestException ("The operation has timed out").
  • The 2.0.0 beta versions of the port (with CancellationToken parameters) 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_BRIDGE_ALL_HOSTS true routes every host to Graph, on-premises Exchange Server included; see below
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 = "...",
});

Exchange Server URL, mailboxes in Exchange Online

By default only calls to Exchange Online go to Microsoft Graph, and calls to any other host stay on EWS. When the mailboxes have moved to Exchange Online but the application still calls an Exchange Server URL, such as https://mail.contoso.com/EWS/Exchange.asmx, set SUNSETLESS_BRIDGE_ALL_HOSTS=true (or BridgeAllHosts = true in the options). Calls to every host then go to Microsoft Graph, and the application's configuration stays as it is.

The library signs in as the app registration, so the user name and password the code sets for Exchange Server are not used. Name the mailbox with ImpersonatedUserId or SUNSETLESS_DEFAULT_MAILBOX. Autodiscover is unaffected: it is answered from Microsoft Graph for Exchange Online mailboxes and goes to Exchange for the rest.

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.

Inside a component

A component or SDK that ships this package inside it, for other developers to build on, supplies its own license key in its code:

Sunsetless.Ews.SunsetlessEws.UseComponentLicense("...");

The call routes nothing by itself: until the application configures a tenant, every ExchangeService keeps using EWS, and the application needs no key of its own. A key issued for a component works only when the assembly that makes the call has the strong-name public key token the key names, so make the call from the component's own assembly, not through reflection. The same key in SUNSETLESS_LICENSE_KEY or LicenseKey is refused. When the application sets a key of its own, that key is checked first.

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, Autodiscover (MailboxSettings.Read is enough for it)
User.Read.All, Group.Read.All ResolveNames, ExpandDL, FindPeople in the directory, user photos, GetPasswordExpirationDate; User.Read.All also for Autodiscover
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. The answer needs User.Read.All and MailboxSettings.Read; without them Autodiscover goes to Exchange. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.0 82 10/11/2026
2.0.0 85 10/8/2026
1.2.1 94 10/6/2026
1.2.0 95 10/6/2026
1.1.0 99 10/4/2026

Strong name: Microsoft.Exchange.WebServices.NETStandard.dll and Sunsetless.Ews.Core.dll are signed with the Sunsetless key (public key token 1b8c25c6fc94dcf1), so strong-named .NET Framework applications and components can reference them. This changes the assembly identity: on .NET Framework, rebuild every project that references the library against this version, because assemblies compiled against 1.2.1 or earlier, or against the port (Microsoft.Exchange.WebServices.NETStandard 1.1.x), do not load the signed DLL. On .NET 8, 9 and 10 nothing changes, and libraries compiled against the port keep working without a rebuild. Components that ship the library can supply their own license key with SunsetlessEws.UseComponentLicense. FindItem cuts long extended property values (PR_BODY, PR_HTML and others) to 255 characters or 510 bytes in every query path, as Exchange Online does, and BodyType.HTML returns a plain-text message as HTML. GetConversationItems returns the extended properties of a message as Exchange Online does: only those in its conversation view, with strings cut to 255 characters, while meeting messages, posts and messages with voting come back in full. GetConversationItems orders nodes as Exchange Online does: newest first when no SortOrder is sent (the EWS Managed API overload that takes a list of conversations never sends one), replies newest first in TreeOrderAscending, and MaxItemsToReturn keeps the newest items. SUNSETLESS_BRIDGE_ALL_HOSTS=true (BridgeAllHosts in the options) sends calls to every host to Microsoft Graph, Exchange Server included, for applications that still call an Exchange Server URL after their mailboxes moved to Exchange Online. Supported operations, verification against live Exchange Online and known differences: https://sunsetless.com/compatibility