Windows環境
郵件發送失敗
Exchange 2010和2013可以限制用戶發送的郵件數量;通過Power Shell命令新建一條策略規則,給recipientratelimit和messageratelimit兩個參數賦予一定的值,再給用戶應用此規則即可實現限制用戶發送量的效果。
參數說明:
messageratelimit:限制用戶每分鍾可以發送的最大郵件數量,如每分鍾內發送的量超過限制,郵件將停留在發件箱,郵件被延遲到下一分鍾,並最終被發送成功。
recipientratelimit:限制用戶24小時內的發送的最大郵件數量,如發送超過限制,將收到超過限額的NDR退信消息。
注:通訊組(包括動態通訊組)算一個收件人。
參考:Exchange2010\2013限制用戶每分鍾與每天發送郵件的數量
異常處理要注意
有些方法 執行不成功,例如:郵箱服務器沒有此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:\WoTProject\MeSignClient\MeSign\MeSign.Service.Mail\Exchange\EWSHelper.cs:line 156
at MeSign.Bussiness.Mail.Exchange.ExchangeSpecialHelper.VerifyLoginByGetFolder(String userName, MailAccountServiceModel accoutModel) in F:\WoTProject\MeSignClient\MeSign\MeSign.Bussiness\Mail\Exchange\ExchangeSpecialHelper.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:\WoTProject\MeSignClient\MeSign\ews-managed-api-master\Core\EwsHttpWebRequest.cs:line 120
at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request, CancellationToken token) in F:\WoTProject\MeSignClient\MeSign\ews-managed-api-master\Core\Requests\ServiceRequestBase.cs:line 794
--- End of inner exception stack trace ---
at MeSign.Service.Mail.Exchange.EWSFoldersHelper.GetFolderAsync(ExchangeService service, WellKnownFolderName wellKnown) in F:\WoTProject\MeSignClient\MeSign\MeSign.Service.Mail\Exchange\EWSFoldersHelper.cs:line 95
at MeSign.Bussiness.Mail.Exchange.ExchangeSpecialHelper.VerifyLoginByGetFolder(String userName, MailAccountServiceModel accoutModel) in F:\WoTProject\MeSignClient\MeSign\MeSign.Bussiness\Mail\Exchange\ExchangeSpecialHelper.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:\WoTProject\MeSignClient\MeSign\ews-managed-api-master\Core\EwsUtilities.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上不用加此配置。