SSL握手异常:尝试建立SSL或TLS连接时发生错误。

19

我正在尝试使用imap访问gmail邮件,但代码在ssl握手时失败,没有显示任何错误。如果有人能帮忙,请万分感激。我是使用xunit,.NET Core 2.1构建的。我正在使用MailKit Nuget

   public GMailHandler(string mailServer, int port, bool ssl, string login, string password)

          //mailServer = imap.gmail.com
          //port = 993
          //ssl = true

          {

                  if (ssl)

                         Client.Connect(mailServer, port);

                  else

                         Client.Connect(mailServer, port);

                  Client.Authenticate(login, password);

                  Client.Inbox.Open(FolderAccess.ReadOnly);

          }

这回答解决了你的问题吗?使用IMAP访问电子邮件 - jazb
Yohan:请选择@jstedfast的答案,它非常全面,可以帮助人们更快地找到所有情况的正确答案。 - MJBZA
4个回答

37

以下是从MailKit FAQ中复制并粘贴出来的内容:

问:当我尝试连接时,为什么会出现"MailKit.Security.SslHandshakeException: An error occurred while attempting to establish an SSL or TLS connection."

当您遇到具有该错误消息的异常时,通常意味着您遇到了以下情况之一:

1. 邮件服务器不支持在指定端口上使用SSL。

使用邮件服务器进行SSL/TLS加密有两种不同的方式。

第一种方式是在连接到SMTP、POP3或IMAP服务器时立即启用SSL/TLS加密。这种方法需要一个“SSL端口”,因为协议定义的标准端口是用于纯文本通信的。

第二种方式是通过一个可选的STARTTLS命令(对于POP3而言是STLS)来实现。邮件服务器可以选择性地支持它。

下面是MailKit支持的协议以及标准纯文本端口(这些端口不支持任何SSL/TLS加密,或者只支持通过STARTTLS命令扩展)和需要在成功连接到远程主机后立即进行SSL/TLS加密的SSL端口的表格。

|Protocol|Standard Port|SSL Port|
|:------:|:-----------:|:------:|
| SMTP   | 25 or 587   | 465    |
| POP3   | 110         | 995    |
| IMAP   | 143         | 993    |

使用正确的SecureSocketOptions连接到端口非常重要。

如果您要连接上面的标准端口之一,则需要使用SecureSocketOptions.NoneSecureSocketOptions.StartTlsSecureSocketOptions.StartTlsWhenAvailable

如果您要连接SSL端口之一,则需要使用SecureSocketOptions.SslOnConnect

您还可以尝试使用SecureSocketOptions.Auto,它通过比较指定端口与上表中的端口来选择要使用的适当选项。

2. 您连接的邮件服务器使用过期(或不受信任)的SSL证书。

通常情况下,邮件服务器会使用自签名证书,而不是使用由可信证书颁发机构签名的证书。另一个潜在的问题是当本地安装的反病毒软件替换证书以扫描Web流量中的病毒时。

当您的系统无法验证邮件服务器的证书,因为它没有被已知和信任的证书颁发机构签名时,将会出现上述错误。

您可以通过提供自定义的RemoteCertificateValidationCallback并将其设置为客户端的ServerCertificateValidationCallback属性来解决此问题。

在最简单的示例中,您可以像这样做(虽然我强烈建议在生产中不要这样做):

using (var client = new SmtpClient ()) {
    client.ServerCertificateValidationCallback = (s,c,h,e) => true;

    client.Connect (hostName, port, SecureSocketOptions.Auto);

    // ...
}

通常情况下,您可能希望将证书的Thumbprint属性与已在先前日期验证的已知值进行比较。

您还可以使用此回调提示用户(就像您可能看到Web浏览器执行的那样)是否应信任证书。

3. 证书颁发机构的CRL服务器暂时无法访问其中一张或多张证书。

大多数证书颁发机构都很擅长保持其CRL和/或OCSP服务器全天候可用,但偶尔由于网络问题等其他原因,它们也可能会出现故障或无法访问。当发生这种情况时,检查链中一个或多个证书的吊销状态变得不可能。

要忽略吊销检查,您可以在连接之前将IMAP、POP3或SMTP客户端的CheckCertificateRevocation属性设置为false

using (var client = new SmtpClient ()) {
    client.CheckCertificateRevocation = false;

    client.Connect (hostName, port, SecureSocketOptions.Auto);

    // ...
}

4. 服务器不支持客户端配置的相同SSL/TLS协议集。

MailKit试图跟上最新的安全建议,因此正在持续从默认配置中删除已不再被视为安全的旧版SSL和TLS协议。这通常意味着MailKit的SMTP、POP3和IMAP客户端无法连接仍在使用旧版SSL和TLS协议的服务器。目前,默认情况下不支持的SSL和TLS协议有:SSL v2.0、SSL v3.0和TLS v1.0。

您可以通过设置SMTP、POP3或IMAP客户端的SslProtocols属性值来覆盖MailKit的默认支持的 SSL和TLS协议集合。

例如:

using (var client = new SmtpClient ()) {
    // Allow SSLv3.0 and all versions of TLS
    client.SslProtocols = SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;

    client.Connect ("smtp.gmail.com", 465, true);

    // ...
}

3
client.CheckCertificateRevocation = false;这行代码对我有用。 - DavidC
非常全面的答案。 - MJBZA

3

禁用 Avast 杀毒软件。 这个方法对我有效。


1
请将以下内容翻译成中文:

await client.ConnectAsync(_emailConfig.SmtpServer, _emailConfig.Port, false);

只需在客户端配置中将"useSsl"选项设置为false即可。


这是我最初的做法,大约一年都运行良好,然后突然停止工作并出现主机名不匹配的错误。(服务器上的证书没有更改)切换到使用SecureSocketOptions.None方法后,它又正常工作了。 - Oremac
不建议这样做。如果这样做,任何使用与您相同的无线连接、相同网络、在您的ISP上观察流量或处于能够查看您的互联网流量的位置的人都可以阅读您发送的信息,包括您连接到电子邮件地址时的登录名和密码。 - Mickael Bergeron Néron

0

我通过查看协议解决了一个类似的问题。结果发现,MS Exchange服务器使用Tls 1.0以实现向后兼容。我明确设置了协议,连接成功通过。

var client = new ImapClient();
client.SslProtocols = System.Security.Authentication.SslProtocols.Tls;
client.Connect("servername", 993, SecureSocketOptions.SslOnConnect);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接