System.Net.Mail.SmtpClient經過SSL/TLS協議發送郵件失敗問題解決

1、問題描述

一、問題現象

經過System.Net.Mail.SmtpClient使用SSL/TLS協議發送郵件失敗並報錯
System.Net.Mail.SmtpException: Failure sending mailhtml

詳細報錯信息:git

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)

二、問題緣由

這個問題跟SSL/TLS的協議版本有關係,SSL演化到3.0以後仍是不夠安全,所以又出現了SSL的升級版TLS協議,因爲創建鏈接時的區別又分別被稱爲顯示SSL和隱式SSL。SSL/TLS協議一般是結對出現SSL/TLS,不過你們仍是喜歡簡稱爲SSL。github

目前最新版本是TLS 1.3,其餘可用版本是TLS 1.2和TLS 1.1,其中TLS1.1計劃於2020年棄用

因此,目前主流的郵箱服務商加密協議使用的都是TLS。
可是System.Net.Mail.SmtpClient 不支持較新的TLS協議,具體的TLS協議版本支持狀況MSDN上並未找到相關說明web

截止到2020年3月受影響的框架版本:api

  • .NET Core 2.0-3.1
  • .NET Framework 2.0-4.8

目前微軟MSDN已經將System.Net.Mail.SmtpClient標記爲已過時(obsolete),但源碼中並未標記,也並未給出替代實現。安全

2、解決辦法

一、使用System.Web.Mail

System.Web.Mail.SmtpMail雖然已被標記爲已過時,可是畢竟他支持新的SSL/TLS協議。bash

不過,須要注意的是,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 = "xxx@qq.com";
            //收件人收箱地址
            mmsg.To = "xxx@163.com";
            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);
        }
    }
}

二、使用MailKit

MailKit是一個開源的基於MimeKit的跨平臺郵件收發類庫,支持IMAP、POP三、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", "xxx@qq.com"));
            message.To.Add (new MailboxAddress ("test", "xxx@163.com"));
            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 ("xxx@qq.com", "password");
                client.Send (message);
                client.Disconnect (true);
            }
        }
    }
}

3、備註

一、附錄


本文首發於:https://ken.io/note/smtpclien...

相關文章
相關標籤/搜索