Windows环境
邮件发送失败
Exchange 2010和2013可以限制用户发送的邮件数量;通过Power Shell命令新建一条策略规则,给recipientratelimit和messageratelimit两个参数赋予一定的值,再给用户应用此规则即可实现限制用户发送量的效果。
参数说明:
messageratelimit:限制用户每分钟可以发送的最大邮件数量,如每分钟内发送的量超过限制,邮件将停留在发件箱,邮件被延迟到下一分钟,并最终被发送成功。
recipientratelimit:限制用户24小时内的发送的最大邮件数量,如发送超过限制,将收到超过限额的NDR退信消息。
注:通讯组(包括动态通讯组)算一个收件人。
参考:Exchange20102013限制用户每分钟与每天发送邮件的数量
异常处理要注意
有些方法 执行不成功,例如:邮箱服务器没有此itemId,会报错,直接抛出ServiceResponseException异常,而不是返回null就行
try { Item item = await Item.Bind(service, itemId, propertySet); EmailMessage message = item as EmailMessage; return message; } catch (ServiceResponseException srex) { Debug.WriteLine($"GetEmailSummary:{srex.ErrorCode},{srex.Message}"); return null; } catch (Exception ex) { throw ex; }
或者直接,让外层去捕获异常,外层记录异常日志。。
try { Item item = await Item.Bind(service, itemId, propertySet); EmailMessage message = item as EmailMessage; return message; } catch (Exception ex) { throw ex; }
在获取 标记Flag的邮件时报错
1、System.AggregateException: One or more errors occurred. (该属性不能用于此类型的限制。)
代码:searches.Add(new SearchFilter.IsEqualTo(ItemSchema.Flag, true)); //星标
ItemSchema.Flag
定义Flag属性。 标记字段适用于以Exchange Server 2013为目标的Exchange Online客户端和Exchange版本。
2、System.AggregateException: One or more errors occurred. (扩展的属性特性组合无效。)
new SearchFilter.IsEqualTo(new ExtendedPropertyDefinition(0x1090, MapiPropertyType.Boolen), true))
改为
new SearchFilter.IsEqualTo(new ExtendedPropertyDefinition(0x1090, MapiPropertyType.Integer), true))
3、System.AggregateException: One or more errors occurred. (指定的值对属性无效。)
new SearchFilter.IsEqualTo(new ExtendedPropertyDefinition(0x1090, MapiPropertyType.Integer), true))
改为
new SearchFilter.IsEqualTo(new ExtendedPropertyDefinition(0x1090, MapiPropertyType.Integer), 2));
A time zone with the specified ID could not be found
将service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
改为 service = new ExchangeService(); 不指定则用最新的版本
The request failed.[Content-Type]
具体:The request failed. Cannot process the message because the content type 'text/plain; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'
在直接引用Microsoft.Exchange.WebServices.NETStandard 包的时候没有问题,
但是在 引入源码后,编译为dll去调用的时候,报错。
【因为 引用的是两套代码,引入的包里面的代码是官网(要从包的dll去反编译查看出)的:https://github.com/OfficeDev/ews-managed-api
而你引入的源码很可能是https://github.com/sherlock1982/ews-managed-api】
参考:https://stackoverflow.com/questions/54948180/ews-httpheader-content-type
在sherlock1982(github.com/sherlock1982/ews-managed-api)的EWS分支中找到EwsHttpWebRequest.cs类。在GetResponse方法中,在设置消息内容之后立即进行设置(第91行):
message.Content.Headers.Clear( ); message.Content.Headers.Add(“ Content-Type”,“ text / xml; charset = utf-8”);
问题是因为HttpRequestMessage的内容类型不正确,而不是请求本身。 希望这会有所帮助-我知道,答案要晚一年了... :) –
The SSL connection could not be established, see inner exception
在直接引用Microsoft.Exchange.WebServices.NETStandard 包的时候没有问题,
但是在 引入源码后,编译为dll去调用的时候,报错。
场景:用邮箱host对应的ip去模拟登录时报错。
Httpclient想要实现相同的功能,需要在HttpClient中设置。
var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = delegate { return true; } };
参考:HttpClient SSL connection could not be established error
修改源码:
EwsHttpWebRequest.cs类
internal EwsHttpWebRequest(Uri uri) { Method = "GET"; RequestUri = uri; _httpClientHandler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, ServerCertificateCustomValidationCallback = delegate { return true; } //增加这一行 }; _httpClient = new HttpClient(_httpClientHandler); }
发加密签名邮件报错:必需的属性丢失
断点调试,去发现报错的位置,具体信息:
看到ErrorCode:ErrorRequiredPropertyMissing
根据ErrorRequiredPropertyMissing去搜索,找到官网,
定位到问题是Attachments的问题
需要调试下exchange的EmailMessage 中的Attachments 的属性是否都具有:
完整的应该是以下:
获取邮件体 MIME 内容转换失败 ErrorCode = ErrorMimeContentConversionFailed
现象:在获取 未送达的邮件体时报的错。
在Web上查看:如下
可以改用以下方式重新获取
1、首先捕获异常ErrorMimeContentConversionFailed
catch (AggregateException ex) { var exception = ex.InnerException as ServiceResponseException; if (exception != null) serviceError = exception.ErrorCode; }
2、 调用处:
EmailMessage emailMessage = EWSItemHelper.GetEmailMessageBody(service, itemId, out serviceError); if (emailMessage == null) { if (serviceError == ServiceError.ErrorMimeContentConversionFailed) { var mailDetail = new MailDetailModel(mailInfo); mimeMessage = await DownloadMessage(service, mailDetail, itemId); } }
3、 处理
/// <summary> /// 重新下载邮件信息 /// </summary> /// <param name="exchangeService"></param> /// <param name="mailInfo"></param> /// <param name="itemId"></param> /// <returns></returns> private async Task<MimeMessage> DownloadMessage( ExchangeService exchangeService, MailDetailModel mailInfo, ItemId itemId) { var mail = await EWSItemHelper.GetEmailMessageBodyNew(exchangeService, itemId); List<FileAttachment> fileAttaches = new List<FileAttachment>(); if (mail == null) return null; if (mail.Attachments != null && mail.Attachments.Count() > 0) { foreach (var attachment in mail.Attachments) { if (attachment is FileAttachment) { FileAttachment fileAttachment = attachment as FileAttachment; fileAttaches.Add(fileAttachment); } } } var message = new MimeMessage(); string name = string.Empty; string email = string.Empty; StringFormatHelper.GetNameAndEmailAddress_NotSplitEmail(mailInfo.MailFrom, ref name, ref email); message.From.Add(new MailboxAddress(name, email)); if (!string.IsNullOrEmpty(mailInfo.MailTo)) { //message.To.Add(new MailboxAddress("Alice", "alice@wonderland.com")); } if (!string.IsNullOrEmpty(mailInfo.MailCc)) { //message.Cc.Add(new MailboxAddress("Alice", "alice@wonderland.com")); } message.Subject = mail.Subject; message.Date = mailInfo.MailDate; var builder = new BodyBuilder(); // Set the plain-text version of the message text builder.HtmlBody = mail.Body.Text; //bool isSign = false; foreach (var attach in fileAttaches) { //if (attach.ContentType == "multipart/signed") // isSign = true; // We may also want to attach a calendar event for Monica's party... if (attach != null) builder.Attachments.Add(attach.Name, attach.Content); } // Now we just need to set the message body and we're done message.Body = builder.ToMessageBody(); //if (isSign) //{ //message.Body.Headers.Remove(HeaderId.ContentType); //message.Body.Headers.Add(HeaderId.ContentType, "multipart/signed"); //} return message; } /// <summary> /// 通过ItemId 获取邮件体 /// </summary> /// <param name="service"></param> /// <param name="itemId"></param> /// <returns></returns> public static async Task<EmailMessage> GetEmailMessageBodyNew(ExchangeService service, ItemId itemId) { try { PropertySet properties = new PropertySet(BasePropertySet.FirstClassProperties, ItemSchema.Body, ItemSchema.TextBody, ItemSchema.Subject, ItemSchema.HasAttachments, ItemSchema.Attachments, ItemSchema.ExtendedProperties); Item item = await Item.Bind(service, itemId, properties); if (item == null) return null; EmailMessage message = item as EmailMessage; if (message == null) return null; else return message; } catch (Exception ex) { //throw ex; } return null; }
Linux环境
An item with the same key has already been added. Key: Std/1940
2020-11-02 18:38:38 [1]
System.ArgumentException: An item with the same key has already been added. Key: Std/1940
at MeSign.Service.Mail.Exchange.EWSHelper.GetExchageVersionString(String email, String password, String url, StringBuilder log) in F:WoTProjectMeSignClientMeSignMeSign.Service.MailExchangeEWSHelper.cs:line 156
at MeSign.Bussiness.Mail.Exchange.ExchangeSpecialHelper.VerifyLoginByGetFolder(String userName, MailAccountServiceModel accoutModel) in F:WoTProjectMeSignClientMeSignMeSign.BussinessMailExchangeExchangeSpecialHelper.cs:line 380
方案:
Linux断点调试
搭建 deepin(安装netcore3.1),利用vs远程调试,发现:
TimeZoneTransitionGroup.cs类 InitializeFromAdjustmentRule中有字典 添加错误
The request failed.[GSSAPI]
2020-11-02 19:45:19 [1]
Microsoft.Exchange.WebServices.Data.ServiceRequestException: The request failed. GSSAPI operation failed with error - An unsupported mechanism was requested. NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.
---> Microsoft.Exchange.WebServices.Data.EwsHttpClientException: GSSAPI operation failed with error - An unsupported mechanism was requested. NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.
at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.GetResponse(CancellationToken token) in F:WoTProjectMeSignClientMeSignews-managed-api-masterCoreEwsHttpWebRequest.cs:line 120
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request, CancellationToken token) in F:WoTProjectMeSignClientMeSignews-managed-api-masterCoreRequestsServiceRequestBase.cs:line 794
--- End of inner exception stack trace ---
at MeSign.Service.Mail.Exchange.EWSFoldersHelper.GetFolderAsync(ExchangeService service, WellKnownFolderName wellKnown) in F:WoTProjectMeSignClientMeSignMeSign.Service.MailExchangeEWSFoldersHelper.cs:line 95
at MeSign.Bussiness.Mail.Exchange.ExchangeSpecialHelper.VerifyLoginByGetFolder(String userName, MailAccountServiceModel accoutModel) in F:WoTProjectMeSignClientMeSignMeSign.BussinessMailExchangeExchangeSpecialHelper.cs:line 413
利用测试Demo调试,当部署目标为.net core 2.0时可以
2.0以上的.net core 2.2 、.net core3+不行
参考:https://github.com/dotnet/runtime/issues/28530
【从.NET Core 2.1开始,默认的HTTP堆栈基于SocketsHttpHandler。
SocketsHttpHandler使用GSSAPI来处理“协商”和“ NTLM”的HTTP AUTH方案。
在* Nix和OSX计算机上,这需要为Kerberos和NTLM安装GSSAPI支持软件包。
.NET Core的默认Docker映像不包含NTLM支持包(即gss-ntlmssp)。 结果,由于未在计算机上安装与NTLM相关的软件包,因此HttpClient在尝试对NTLM服务器进行身份验证时将引发异常。】
Excahnge源代码中查找"NTLM"
credentialCache.Add(url, "NTLM", networkCredentials);
也有报错:
System.ComponentModel.Win32Exception (0x80090020): GSSAPI operation failed with error - An unsupported mechanism was requested. NTLM authentication requires the GSSAPI plugin 'gss-ntlmssp'.
解决方式:
https://stackoverflow.com/questions/52266659/net-core-spnego-auth-with-httpclient
https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-2-1#sockets-improvements
static void Main(string[] args) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); Console.WriteLine("运行平台是linux"); } }
Unable to load shared library 'System.Net.Http.Native' or one of its dependencies.
{System.TypeInitializationException: The type initializer for 'System.Net.Http.CurlHandler' threw an exception.
---> System.TypeInitializationException: The type initializer for 'Http' threw an exception.
---> System.TypeInitializationException: The type initializer for 'HttpInitializer' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'System.Net.Http.Native' or one of its dependencies.
In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: libSystem.Net.Http.Native:
cannot open shared object file: No such file or directory
at Interop.Http.GetSslVersionDescription()
at Interop.HttpInitializer..cctor()
--- End of inner exception stack trace ---
at Interop.Http..cctor()
--- End of inner exception stack trace ---
at Interop.Http.GetSupportedFeatures()
at System.Net.Http.CurlHandler..cctor()
--- End of inner exception stack trace ---
at System.Net.Http.CurlHandler..ctor()
参考官网:https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netcore-3.1
从.NET Core 2.1开始,HttpClientHandler类的实现已更改为基于System.Net.Http.SocketsHttpHandler类使用的跨平台HTTP协议堆栈。 在.NET Core 2.1之前,HttpClientHandler类使用较旧的HTTP协议栈(Windows上的WinHttpHandler和CurlHandler,这是在Linux的本机libcurl组件之上实现的内部类)。
您可以通过以下三种方式之一将应用程序配置为使用旧的HTTP协议栈:
1、AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); //使用旧的协议
2、Define the System.Net.Http.UseSocketsHttpHandler switch in the .netcore.runtimeconfig.json configuration file
"runtimeOptions": {
"configProperties": {
"System.Net.Http.UseSocketsHttpHandler": false
}
}
这个修改配置文件是最终解决方案。。
参考:
https://github.com/dotnet/runtime/issues/28891
这是因为System.Net.Http.Native具有libcurl.so.4的依赖性。 那就是到构建服务器上libcurl3的链接。 那还算不错,但是Ubuntu使用符号版本控制。
因此,即使我们依赖于libcurl4,我们也需要libcurl3符号。
在Ubuntu 18上,我们仍然可以打开共享库,但是符号不匹配:
是的,在将来的某个时候,我们将从主分支和libcurl依赖项中删除CurlHandler。 但是我们还没有与SocketsHttpHandler实现功能对等。 我们需要完成HTTP / 2工作。 因此,删除CurlHandler可能是.NET Core 3.0之后的事情。
鉴于它是主要版本,我们至少可以仔细考虑删除.NET Core 3的含义,因为我们可以通过这种更改更加灵活。 IIRC,阻碍我们发展的主要因素是HTTP / 2支持和更好的代理支持,这两者都应在3.0中解决。
无论如何,我们的目标都是完全可选,默认情况下处于关闭状态,并且.NET Core可以从源代码构建而无需libcurl依赖。 至少我们应该努力确保3.0的情况如此。
参考:netcore程序部署 ubuntu 16.0.4 报错 The type initializer for 'System.Net.Http.CurlHandler'的解决方案
当有人明确需要curlhttphandler时,解决方法是安装旧的libcurl3
1、http协议栈,使用旧的协议
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); //使用旧的协议
报错:The type initializer for 'System.Net.Http.CurlHandler' threw an exception.
可能需要装liburl3
2、http协议栈,使用新的协议
SocketsHttpHandler
注意:Linux上发布时
发布后,在配置文件mesignpc.runtimeconfig.json
增加配置,即:
{
"runtimeOptions": {
"tfm": "netcoreapp3.1",
"includedFrameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "3.1.11"
}
]
,
"configProperties": {
"System.Net.Http.UseSocketsHttpHandler": false
}
}
}
Unable to convert 1946-04-21T00:00:00.000 from (UTC+08:00) 香港标准时间 to (UTC) Coordinated Universal Time.
具体报错:
{Microsoft.Exchange.WebServices.Data.TimeZoneConversionException:
Unable to convert 1946-04-21T00:00:00.000 from (UTC+08:00) 香港标准时间 to (UTC) Coordinated Universal Time.
---> System.ArgumentException: The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid. (Parameter 'dateTime')
at System.TimeZoneInfo.ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags, CachedData cachedData)
at System.TimeZoneInfo.ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone)
at Microsoft.Exchange.WebServices.Data.EwsUtilities.ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone) in F:WoTProjectMeSignClientMeSignews-managed-api-masterCoreEwsUtilities.cs:line 753
--- End of inner exception stack trace ---
资料:https://github.com/OfficeDev/ews-managed-api/issues/13
于是将
service = new ExchangeService(eWSInitModel.ExchangeVersion);
修改为
service = new ExchangeService(eWSInitModel.ExchangeVersion, TimeZoneInfo.Utc);
ServiceVersionException: The property WellKnownFolderName is valid only for Exchange Exchange2013 or later versions.
需要调用WellKnownFolderName属性,则必须是Exchange服务器的版本必须是Exchange2013及以上。
Mac环境:
Request failed
MoveNext throw a exception:Microsoft.Exchange.WebServices.Data.ServiceRequestException: The request failed. The handler does not support custom handling of certificates on this operating system. Consider using System.Net.Http.SocketsHttpHandler.
---> Microsoft.Exchange.WebServices.Data.EwsHttpClientException: The handler does not support custom handling of certificates on this operating system. Consider using System.Net.Http.SocketsHttpHandler.
at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.GetResponse(CancellationToken token)
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request, CancellationToken token)
--- End of inner exception stack trace ---
at MeSign.Service.Mail.Exchange.EWSFoldersHelper.GetFolderAsync(ExchangeService service, WellKnownFolderName wellKnown)
at MeSign.Bussiness.Mail.Exchange.ExchangeSpecialHelper.VerifyLoginByGetFolder(String userName, MailAccountServiceModel accoutModel)
处理程序不支持此操作系统上证书的自定义处理。 考虑使用System.Net.Http.SocketsHttpHandler。
原因:
是因为mesignpc.runtimeconfig.json 配置文件中加了"System.Net.Http.UseSocketsHttpHandler": false
从报错可以看出,mac上不用加此配置。