Exchange Online EWS调用返回无效XML错误排查求助
解决EWS OAuth认证发送邮件时的"The response received from the service didn't contain valid XML"错误
问题描述
我使用以下代码通过OAuth认证Exchange Online(Exchange 365)服务器并发送邮件,但收到错误提示:"The response received from the service didn't contain valid XML"。已参考官方文档配置,Entra应用设置正确。
代码示例
using System.Diagnostics; using Microsoft.Exchange.WebServices.Data; using Microsoft.Identity.Client; using Task = System.Threading.Tasks.Task; namespace My.Sandbox.CoreConsoleApp; internal class Program { // ReSharper disable once IdentifierTypo private const string MyEntraAppClientId = "client-id"; // ReSharper disable once IdentifierTypo private const string MyEntraAppTenantId = "tenant-id"; private const string MyClientSecretValue = "client-secret-value"; // ReSharper disable once IdentifierTypo private const string MyEntraAppRedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"; private const string Outlook365EndpointUrl = "https://outlook.office365.com/EWS/Exchange.asmx"; /// <summary> /// Specifies the primary mailbox against which operations should be performed. Useful in scenarios involving /// multiple mailboxes or delegate access. Ensures accurate handling of tasks by directing requests /// to the intended mailbox, facilitating secure and contextually relevant operations within Exchange environments. /// </summary> // ReSharper disable once InconsistentNaming // ReSharper disable once IdentifierTypo private const string Headers_XAnchormailbox = "X-AnchorMailbox"; private static void Main(string[] args) { Task.Run(() => ConnectUsingAppOnlyAuthentication("my-email-address@My2.onmicrosoft.com")).Wait(); } private static async Task ConnectUsingAppOnlyAuthentication(string accountAddress) { try { var authResult = GetToken(); // Configure the ExchangeService with the access token var ewsClient = new ExchangeService { Url = new Uri(MyEntraAppRedirectUri), Credentials = new OAuthCredentials(authResult.AccessToken), ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, accountAddress) }; // ReSharper disable once CommentTypo //Include x-anchormailbox header ewsClient.HttpHeaders.Add(Headers_XAnchormailbox, accountAddress); var email = new EmailMessage(ewsClient); email.ToRecipients.Add("test-target-email@gmail.com"); email.Subject = "HelloWorld"; email.Body = new MessageBody("This is the first email I've sent by using the EWS Managed API."); await email.SendAndSaveCopy(); } catch (MsalException ex) { Console.WriteLine($"Error acquiring access token: {ex}"); } catch (Exception ex) { Console.WriteLine($"Error: {ex}"); } if (Debugger.IsAttached) { Console.WriteLine(@"Hit any key to exit..."); Console.ReadKey(); } } private static AuthenticationResult GetToken() { // Using Microsoft.Identity.Client 4.22.0 var applicationBuilder = ConfidentialClientApplicationBuilder .Create(MyEntraAppClientId) .WithClientSecret(MyClientSecretValue) .WithTenantId(MyEntraAppTenantId) .Build(); // The permission scope required for EWS access var ewsScopes = new string[] { Scope.Outlook365_Default.Value }; // Make the token request return applicationBuilder.AcquireTokenForClient(ewsScopes).ExecuteAsync().Result; } /// <summary> /// Represents an OAuth scope, which determines the resources and application can access /// and the actions it can perform. /// </summary> [DebuggerDisplay("{Value}")] internal class Scope { #region constructors private Scope(string value) { Value = value; } #endregion #region properties public string Value { get; } #endregion #region static members // ReSharper disable once InconsistentNaming public static readonly Scope Outlook365_Ews_AccessAsUser_All = new("https://outlook.office365.com/EWS.AccessAsUser.All"); /// <summary> /// The default scope for Exchange Online ("https://outlook.office365.com/.default") /// </summary> public static readonly Scope Outlook365_Default = new("https://outlook.office365.com/.default"); #endregion } }
异常信息(中文翻译)
Microsoft.Exchange.WebServices.Data.ServiceRequestException: 从服务接收的响应不包含有效的XML。 ---> System.Xml.XmlException: 缺少根元素。 在 System.Xml.XmlTextReaderImpl.Throw(Exception e) 在 System.Xml.XmlTextReaderImpl.ParseDocumentContent() 在 System.Xml.XmlTextReaderImpl.Read() 在 System.Xml.XmlAsyncCheckReader.Read() 在 System.Xml.XmlCharCheckingReader.Read() 在 Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read() 在 Microsoft.Exchange.WebServices.Data.EwsXmlReader.Read(XmlNodeType nodeType) 在 Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadXmlDeclaration(EwsServiceXmlReader reader) --- 内部异常堆栈跟踪结束 --- 在 Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadXmlDeclaration(EwsServiceXmlReader reader) 在 Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadPreamble(EwsServiceXmlReader ewsXmlReader) 在 Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ReadResponse(EwsServiceXmlReader ewsXmlReader, WebHeaderCollection responseHeaders) 在 Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponseXml(Stream responseStream, WebHeaderCollection responseHeaders) 在 Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.ReadResponse(IEwsHttpWebResponse response) 在 Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.<InternalExecuteAsync>d__1.MoveNext() --- 之前引发异常的位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() 在 Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.<ExecuteAsync>d__6.MoveNext() --- 之前引发异常的位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult() 在 Microsoft.Exchange.WebServices.Data.Item.<InternalCreate>d__12.MoveNext() --- 之前引发异常的位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult() 在 Microsoft.Exchange.WebServices.Data.EmailMessage.<InternalSend>d__6.MoveNext() --- 之前引发异常的位置的堆栈跟踪结束 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 在 System.Runtime.CompilerServices.TaskAwaiter.GetResult()
解决方案
- 核心错误修正:你把OAuth跳转地址
MyEntraAppRedirectUri赋值给了ExchangeService.Url,这是错误的。EWS客户端需要指向Exchange Online的EWS端点,把这一行代码修改为:Url = new Uri(Outlook365EndpointUrl), - 优化异步调用:当前
GetToken方法用Result同步阻塞获取Token,建议改为异步实现,避免死锁风险:
然后在private static async Task<AuthenticationResult> GetTokenAsync() { var applicationBuilder = ConfidentialClientApplicationBuilder .Create(MyEntraAppClientId) .WithClientSecret(MyClientSecretValue) .WithTenantId(MyEntraAppTenantId) .Build(); var ewsScopes = new string[] { Scope.Outlook365_Default.Value }; return await applicationBuilder.AcquireTokenForClient(ewsScopes).ExecuteAsync(); }ConnectUsingAppOnlyAuthentication中调用:var authResult = await GetTokenAsync(); - 权限确认:因为是应用-only模式,确保Entra应用已添加
EWS.AccessAsApp应用权限,并且完成了管理员同意操作。
内容的提问来源于stack exchange,提问作者user884248
相关产品推荐
相关产品推荐

