System.Net.Mail.SmtpClient通过SSL/TLS协议发送邮件失败问题解决

摘要:
SSL/TLS协议通常是结对出现SSL/TLS,不过大家还是喜欢简称为SSL。但是System.Net.Mail.SmtpClient不支持较新的TLS协议,具体的TLS协议版本支持情况MSDN上并未找到相关说明截止到2020年3月受影响的框架版本:.NETCore2.0-3.1.NETFramework2.0-4.8目前微软MSDN已经将System.Net.Mail.SmtpClient标记为已过期,但源码中并未标记,也并未给出替代实现。

一、问题描述

1、问题现象

通过System.Net.Mail.SmtpClient使用SSL/TLS协议发送邮件失败并报错
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 = "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);
        }
    }
}

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", "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);
            }
        }
    }
}

三、备注

1、附录


本文首发于:https://ken.io/note/smtpclient-sending-mail-failure-via-ssl-or-tls-solved

免责声明:文章转载自《System.Net.Mail.SmtpClient通过SSL/TLS协议发送邮件失败问题解决》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇IBM MQ 集成CXF 发送JMS 消息C#的队列(Queue,ConcurrentQueue)和堆栈(Stack,ConcurrentStack)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[转]C# 将类的内容写成JSON格式的字符串

将类的内容写入到JSON格式的字符串中 本例中建立了Person类,赋值后将类中内容写入到字符串中 运行本代码需要添加引用动态库Newtonsoft.Json 程序代码: using System; using System.Collections.Generic; using System.Linq; using System.Text; using S...

c# WinForm调用控制台

由于Windows控制台程序是封装在kernel32.dll,所以有必要讲述一下WinForm如何调用动态链接库的步骤。 1.首先需要在调用窗体中申明using System.Runtime.InteropServices; 2.其次需要在C#语言源程序中声明外部方法,格式如下: [DLLImport(“DLL文件”)] 修饰符 extern 返回变量类型...

快速编译system.img和boot.img的方法

快速编译system.img,可以使用这个命令: #make systemimage  快速编译boot.img,可以使用以下命令: #make bootimage  快速编译userdata.img,可以使用以下命令: # make userdataimage-nodeps 但是,对于bootimage, 在不改变内存布局的情况下,可以使用以下命令: #...

winForm 打印预览

  自己很少写技术博客,虽然已经干程序员两年多了,winform开发,web开发都干过,不论项目大小对于.net的相关技术也是了解的,如mvc,wcf,wpf,silverlight,socekt通讯,nhibernate,spring.net wp手机开发等,但是最终发现还是软件架构比所谓的单一功能更为系统化。  下面是一个小的例子 Winfom打印预览...

[转]用JAVA在读取EXCEL文件时如何判断列隐藏

原文地址:https://www.cnblogs.com/OwenWu/archive/2012/01/03/2310620.html org.apache.poi.hssf.usermodel.HSSFSheet  public static void main(String[] args) throws IOException { String pat...

Java 简单的excel读写操作

描述:简单的对excel的第一个Sheet表的读写操作 依赖包:apache.poi/poi-3.14、apache.poi/poi-ooxml-3.14 package excel; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel....