【问题标题】:Testing SMTP server is running via C#测试 SMTP 服务器正在通过 C# 运行
【发布时间】:2010-12-10 15:25:02
【问题描述】:

如何在不发送消息的情况下通过 C# 测试 SMTP 是否启动并运行。

我当然可以试试:

try{
// send email to "nonsense@example.com"
}
catch
{
// log "smtp is down"
}

必须有一个更整洁的方法来做到这一点。

【问题讨论】:

    标签: c# smtp


    【解决方案1】:

    您可以尝试saying EHLO 到您的服务器,看看它是否响应250 OK。当然这个测试并不能保证你以后能成功发送邮件,但它是一个很好的迹象。

    这是一个示例:

    class Program
    {
        static void Main(string[] args)
        {
            using (var client = new TcpClient())
            {
                var server = "smtp.gmail.com";
                var port = 465;
                client.Connect(server, port);
                // As GMail requires SSL we should use SslStream
                // If your SMTP server doesn't support SSL you can
                // work directly with the underlying stream
                using (var stream = client.GetStream())
                using (var sslStream = new SslStream(stream))
                {
                    sslStream.AuthenticateAsClient(server);
                    using (var writer = new StreamWriter(sslStream))
                    using (var reader = new StreamReader(sslStream))
                    {
                        writer.WriteLine("EHLO " + server);
                        writer.Flush();
                        Console.WriteLine(reader.ReadLine());
                        // GMail responds with: 220 mx.google.com ESMTP
                    }
                }
            }
        }
    }
    

    这是list of codes 期待。

    【讨论】:

    • 喜欢它 - 非常喜欢它!好一个达林!
    • @Darin Dimitrov tanx 为您解答.. 无论如何要检查用户名和密码(smtp 身份验证)是否有效?我在stackoverflow.com/questions/17319276/… 中问过。请帮助我
    • 这似乎不够。要正确测试 SMTP 设置,您至少应该使用一些外部电子邮件地址(例如postmaster@example.com)执行RCPT TO,但在发送DATA 之前先退出。这实际上将测试您是否具有中继权限,实际上是验证您的用户名/密码和/或客户端证书。
    【解决方案2】:

    我使用此方法和类来验证凭据 (link to github):

    public static bool ValidateCredentials(string login, string password, string server, int port, bool enableSsl) {
            SmtpConnectorBase connector;
            if (enableSsl) {
                connector = new SmtpConnectorWithSsl(server, port);
            } else {
                connector = new SmtpConnectorWithoutSsl(server, port);
            }
    
            if (!connector.CheckResponse(220)) {
                return false;
            }
    
            connector.SendData($"HELO {Dns.GetHostName()}{SmtpConnectorBase.EOF}");
            if (!connector.CheckResponse(250)) {
                return false;
            }
    
            connector.SendData($"AUTH LOGIN{SmtpConnectorBase.EOF}");
            if (!connector.CheckResponse(334)) {
                return false;
            }
    
            connector.SendData(Convert.ToBase64String(Encoding.UTF8.GetBytes($"{login}")) + SmtpConnectorBase.EOF);
            if (!connector.CheckResponse(334)) {
                return false;
            }
    
            connector.SendData(Convert.ToBase64String(Encoding.UTF8.GetBytes($"{password}")) + SmtpConnectorBase.EOF);
            if (!connector.CheckResponse(235)) {
                return false;
            }
    
            return true;
        }
    

    SmtpConnectorBase:

    internal abstract class SmtpConnectorBase {
        protected string SmtpServerAddress { get; set; }
        protected int Port { get; set; }
        public const string EOF = "\r\n";
    
        protected SmtpConnectorBase(string smtpServerAddress, int port) {
            SmtpServerAddress = smtpServerAddress;
            Port = port;
        }
    
        public abstract bool CheckResponse(int expectedCode);
        public abstract void SendData(string data);
    }
    

    SmtpConnectorWithoutSsl:

    internal class SmtpConnectorWithoutSsl : SmtpConnectorBase {
        private Socket _socket = null;
    
        public SmtpConnectorWithoutSsl(string smtpServerAddress, int port) : base(smtpServerAddress, port) {
            IPHostEntry hostEntry = Dns.GetHostEntry(smtpServerAddress);
            IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], port);
            _socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            //try to connect and test the rsponse for code 220 = success
            _socket.Connect(endPoint);
    
        }
    
        ~SmtpConnectorWithoutSsl() {
            try {
                if (_socket != null) {
                    _socket.Close();
                    _socket.Dispose();
                    _socket = null;
                }
            } catch (Exception) {
                ;
            }
    
        }
    
        public override bool CheckResponse(int expectedCode) {
            while (_socket.Available == 0) {
                System.Threading.Thread.Sleep(100);
            }
            byte[] responseArray = new byte[1024];
            _socket.Receive(responseArray, 0, _socket.Available, SocketFlags.None);
            string responseData = Encoding.UTF8.GetString(responseArray);
            int responseCode = Convert.ToInt32(responseData.Substring(0, 3));
            if (responseCode == expectedCode) {
                return true;
            }
            return false;
        }
    
        public override void SendData(string data) {
            byte[] dataArray = Encoding.UTF8.GetBytes(data);
            _socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None);
        }
    }
    

    SmtpConnectorWithSsl:

    internal class SmtpConnectorWithSsl : SmtpConnectorBase {
        private SslStream _sslStream = null;
        private TcpClient _client = null;
    
        public SmtpConnectorWithSsl(string smtpServerAddress, int port) : base(smtpServerAddress, port) {
            TcpClient client = new TcpClient(smtpServerAddress, port);
    
            _sslStream = new SslStream(
                client.GetStream(),
                false,
                new RemoteCertificateValidationCallback(ValidateServerCertificate),
                null
                );
            // The server name must match the name on the server certificate.
            try {
                _sslStream.AuthenticateAsClient(smtpServerAddress);
            } catch (AuthenticationException e) {
                _sslStream = null;
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null) {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine("Authentication failed - closing the connection.");
                client.Close();
            }
        }
    
        ~SmtpConnectorWithSsl() {
            try {
                if (_sslStream != null) {
                    _sslStream.Close();
                    _sslStream.Dispose();
                    _sslStream = null;
                }
            } catch (Exception) {
                ;
            }
    
            try {
                if (_client != null) {
                    _client.Close();
                    _client = null;
                }
            } catch (Exception) {
                ;
            }
        }
    
        // The following method is invoked by the RemoteCertificateValidationDelegate.
        private static bool ValidateServerCertificate(
              object sender,
              X509Certificate certificate,
              X509Chain chain,
              SslPolicyErrors sslPolicyErrors) {
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;
    
            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
    
            // Do not allow this client to communicate with unauthenticated servers.
            return false;
        }
    
        public override bool CheckResponse(int expectedCode) {
            if (_sslStream == null) {
                return false;
            }
            var message = ReadMessageFromStream(_sslStream);
            int responseCode = Convert.ToInt32(message.Substring(0, 3));
            if (responseCode == expectedCode) {
                return true;
            }
            return false;
        }
    
        public override void SendData(string data) {
            byte[] messsage = Encoding.UTF8.GetBytes(data);
            // Send hello message to the server. 
            _sslStream.Write(messsage);
            _sslStream.Flush();
        }
    
        private string ReadMessageFromStream(SslStream stream) {
            byte[] buffer = new byte[2048];
            StringBuilder messageData = new StringBuilder();
            int bytes = -1;
            do {
                bytes = stream.Read(buffer, 0, buffer.Length);
    
                // Use Decoder class to convert from bytes to UTF8
                // in case a character spans two buffers.
                Decoder decoder = Encoding.UTF8.GetDecoder();
                char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
                decoder.GetChars(buffer, 0, bytes, chars, 0);
                messageData.Append(chars);
                // Check for EOF.
                if (messageData.ToString().IndexOf(EOF) != -1) {
                    break;
                }
            } while (bytes != 0);
    
            return messageData.ToString();
        }
    }
    

    【讨论】:

    • 在 SmtpConnectorWithoutSsl 中有一个无限循环。在 CheckResponse 方法中, while (_socket.Available == 0) 行应该有一个限制。我遇到了一个场景,其中 _socket.Available 永远不会等于 0。但是,除此之外 - 这很完美。使用它大约 6 个月没有问题。
    • @Samidjo 我不确定您在哪里看到该变体,但我在产生无限循环的代码中的任何地方都看不到它。用我的手机写这个。如果 100 是默认值,那么我记得它并没有停在 100 上。在我的用例中这是无限循环。
    • @Samidjo 我的建议是尝试一下。将我声明的行设置为始终 = 0,并打印出一个计数。我愿意打赌它会超过 100。
    • @HeribertoLugo 采用新版本,上面是旧版本。转到 git 存储库,您将看到变量 MAX_ATTEMPTS_COUNT。
    • @Samidjo 不知道你为什么删除了你的其他评论,看起来我在自言自语。代码无关紧要。这是几年前的事了,我已经在需要的地方修好了。无需将代码更改为新代码。它有效,解决了小问题。我发表评论是为了提醒其他人,他们可能会像我一样从这里获取代码。
    【解决方案3】:

    您可以使用套接字或TcpClient 打开端口 (25) 并查看它是否响应。

    【讨论】:

      【解决方案4】:

      在端口 25 上打开到 smtp 服务器的套接字连接,看看是否有任何东西。如果没有,则没有 smtp 服务器。

      【讨论】:

        【解决方案5】:

        这是一个不错的开源工具(不仅仅是 MX): http://www.codeproject.com/KB/IP/DNS_NET_Resolver.aspx

        猜你喜欢
        • 2021-05-26
        • 1970-01-01
        • 1970-01-01
        • 2017-08-07
        • 2017-02-26
        • 1970-01-01
        • 2021-05-20
        • 1970-01-01
        • 2020-05-21
        相关资源
        最近更新 更多