首页 > 解决方案 > MailKit - SmtpClient Connect 方法冻结

问题描述

我正在开发一个 Xamarin android 应用程序,在某些时候(成功交易后)该应用程序必须向客户发送信息电子邮件。创建 MimeMessage 实例以及实际发送它的整个过程是通过一个任务完成的。消息(大多数情况下包含链接图像)是完美创建的,但是一旦我调用一个方法来实际发送它,执行就会在那个调用处冻结,整个任务仍然处于活动状态,但在那个时候被冻结。

这是我的SendMail方法,除了MimeMessage参数之外,它还接收一个 MailAccount 类,其中包含有关 smtp 机器、端口和发件人帐户的信息。一旦调用ConnectMailKitSmtpClient实例的方法,我就会遇到我描述的“冻结”行为。我尝试了很多次——甚至没有一次代码超出了那条线。

private static int SendMail(MailAccount account, MimeMessage message)
{
    using (var client = new SmtpClient())
    {
        try
        {
            client.Connect(account.Server, account.Port, false);
        }
        catch (SmtpCommandException)
        {
            return -1;
        }
        catch (SmtpProtocolException)
        {
            return -2;
        }

        client.AuthenticationMechanisms.Remove("XOAUTH2");

        if (client.Capabilities.HasFlag(SmtpCapabilities.Authentication))
        {
            try
            {
                client.Authenticate(account.User, Decrypt(account.Pass));
            }
            catch (AuthenticationException)
            {
                return -3;
            }
            catch (SmtpCommandException)
            {
                return -1;
            }
            catch (SmtpProtocolException)
            {
                return -2;
            }
        }

        int status = 1; //assume success

        try
        {
            client.Send(message);
        }
        catch (SmtpCommandException ex)
        {
            switch (ex.ErrorCode)
            {
                case SmtpErrorCode.MessageNotAccepted:
                    status = -6;
                    break;

                case SmtpErrorCode.SenderNotAccepted:
                    status = -5;
                    break;

                case SmtpErrorCode.RecipientNotAccepted:
                    status = -4;
                    break;

                default:
                    status = -7;
                    break;
            }
        }

        client.Disconnect(true);
        return status;
    }
}

标签: c#xamarin.androidmailkit

解决方案


通常,呼叫挂起client.Connect表明您尝试连接的主机或端口不可用。检查主机和端口是否正确。

如果它们正确的,请确保您使用的是 MailKit 的最新版本,因为Socket.BeginConnect (string, int ...)在支持 IPv6 的操作系统上,这些旧版本有时会尝试在 IPv6 上使用 IPv4 并在某些情况下挂起(例如当病毒扫描程序像使用了 Avast)。

MailKit 的较新版本(>= 2.1.4 和 2.0 之前的版本)对远程主机进行 DNS 查找,并在实例化 Socket(IPv4 与 IPv6)时手动指定要使用的正确地址族,以避免此问题。

挂起也可能是由 SSL/TLS 证书吊销检查与无响应的证书颁发机构进行的。您可以使用以下代码段禁用证书吊销检查:

client.CheckCertificateRevocation = false;

只需确保调用Connect.

通过在 Visual Studio 中创建一个新的控制台应用程序并粘贴以下代码并检查它是否有效,可能值得测试对 SMTP 服务器的访问:

using System;
using System.Threading;
using System.Threading.Tasks;

using MailKit;
using MailKit.Net.Smtp;

namespace ConsoleApp {
    public class Program
    {
        static void Main (string[] args)
        {
            using (var client = new SmtpClient (new ProtocolLogger ("smtp.log"))) {
                using (var cts = new CancellationTokenSource (60000)) {
                    try {
                        client.Connect ("your-host.com", 25, false, cts.Token);
                        client.Disconnect (true);
                    } catch (Exception ex) {
                        Console.WriteLine ("Error connecting: {0}", ex.Message);
                        Console.WriteLine (ex.StackTrace);
                    }
                }
            }
        }
    }
}

smtp.gmail.com了解您的 Android 应用程序是否在连接到端口465( useSsl = true)时遇到问题也会很有趣。


推荐阅读