System.Net.Mail.SmtpClient通過SSL/TLS協議發送郵件失敗問題解決
- 2020 年 3 月 5 日
- 筆記
一、問題描述
1、問題現象
通過System.Net.Mail
使用SSL協議發送郵件失敗並報錯 System.Net.Mail.SmtpException: Failure sending mail
詳細報錯信息:
System.Net.Mail.SmtpException: Failure sending mail. ---> System.IO.IOException: Unable to read data from the transport connection: The connection was closed. at System.Net.Mail.SmtpReplyReaderFactory.ProcessRead(Byte[] buffer, Int32 offset, Int32 read, Boolean readLine) at System.Net.Mail.SmtpReplyReaderFactory.ReadLines(SmtpReplyReader caller, Boolean oneLine) at System.Net.Mail.SmtpReplyReaderFactory.ReadLine(SmtpReplyReader caller) at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port) at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port) at System.Net.Mail.SmtpClient.GetConnection() at System.Net.Mail.SmtpClient.Send(MailMessage message) --- End of inner exception stack trace --- at System.Net.Mail.SmtpClient.Send(MailMessage message)
2、問題原因
這個問題跟SSL/TLS的協議版本有關係,SSL演化到3.0之後還是不夠安全,因此又出現了SSL的升級版TLS協議,由於建立連接時的區別又分別被稱為顯示SSL和隱式SSL。SSL/TLS協議通常是結對出現SSL/TLS,不過大家還是喜歡簡稱為SSL。
目前最新版本是TLS 1.3,其他可用版本是TLS 1.2和TLS 1.1,其中TLS1.1計劃於2020年棄用
所以,目前主流的郵箱服務商加密協議使用的都是TLS。 但是System.Net.Mail.SmtpClient
不支持較新的TLS協議,具體的TLS協議版本支持情況MSDN上並未找到相關說明
截止到2020年3月受影響的框架版本:
- .NET Core 2.0-3.1
- .NET Framework 2.0-4.8
目前微軟MSDN已經將System.Net.Mail.SmtpClient
標記為已過期(obsolete),但源碼中並未標記,也並未給出替代實現。
二、解決辦法
1、使用System.Web.Mail
System.Web.Mail.SmtpMail
雖然已被標記為已過期,但是畢竟他支持新的SSL/TLS協議。
不過,需要注意的是,System.Web.Mail.SmtpMail
,只適用於 .NET Framework(>=2.0)
示例代碼:
using System.Web.Mail; using System; namespace Ken.IO.Util { class Program { public static void Main (string[] args) { MailMessage mmsg = new MailMessage(); mmsg.Subject = "郵件測試主題ken.io"; mmsg.BodyFormat = MailFormat.Html; mmsg.Body = "郵件測試正文ken.io"; mmsg.BodyEncoding = Encoding.UTF8; //優先級 mmsg.Priority = MailPriority.High; //發件者郵箱地址 mmsg.From = "[email protected]"; //收件人收箱地址 mmsg.To = "[email protected]"; mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1"); //用戶名 mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", mmsg.From); //密碼 mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "password"); //端口 mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", 465); //使用SSL mmsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", "true"); //Smtp服務器 SmtpMail.SmtpServer = "smtp.qq.com"; SmtpMail.Send(mmsg); } } }
2、使用MailKit
MailKit是一個開源的基於MimeKit的跨平台郵件收發類庫,支持IMAP、POP3、SMTP。其中SmtpClient也支持TLS協議.
可以很好的支持 .NET Core以及 .NET Framework框架的郵件發送
安裝Nuget Package
#.NET Core dotnet add package MailKit --version 2.5.1 #.NET Framework Install-Package MailKit -Version 2.5.1
示例代碼:
using System; using MailKit.Net.Smtp; using MailKit; using MimeKit; namespace Ken.IO.Util { class Program { public static void Main (string[] args) { var message = new MimeMessage (); message.From.Add (new MailboxAddress ("test", "[email protected]")); message.To.Add (new MailboxAddress ("test", "[email protected]")); message.Subject = "郵件測試"; //html or plain var bodyBuilder = new BodyBuilder (); bodyBuilder.HtmlBody = "<b>郵件測試html正文ken.io</b>"; bodyBuilder.TextBody = "郵件測試文本正文ken.io"; message.Body = bodyBuilder.ToMessageBody(); using (var client = new SmtpClient ()) { client.ServerCertificateValidationCallback = (s,c,h,e) => true; //smtp服務器,端口,是否開啟ssl client.Connect ("smtp.qq.com", 465, true); client.Authenticate ("[email protected]", "password"); client.Send (message); client.Disconnect (true); } } } }
三、備註
1、附錄
- https://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
- https://docs.microsoft.com/zh-cn/dotnet/api/system.net.mail.smtpclient
- https://docs.microsoft.com/zh-cn/dotnet/api/system.web.mail.smtpmail
- https://zh.wikipedia.org/wiki/傳輸層安全性協定