23

这与我前几天问的一个关于如何发送电子邮件的问题有关。

我的新相关问题是……如果我的应用程序的用户位于防火墙后面或其他原因导致线路 client.Send(mail) 不起作用怎么办……

行后:

SmtpClient client = new SmtpClient("mysmtpserver.com", myportID);
client.Credentials = new System.Net.NetworkCredential("myusername.com", "mypassword");

在我尝试发送之前,我可以做些什么来测试客户端吗?

我想过把它放在一个 try/catch 循环中,但我宁愿做一个测试,然后弹出一个对话框说:无法访问 smtp 或类似的东西。

(我假设我和潜在的我的应用程序用户都没有能力调整他们的防火墙设置。例如......他们在工作中安装应用程序并且无法在工作中控制他们的互联网)

-阿迪娜

4

6 回答 6

44

我认为,如果您正在寻找测试 SMTP,那么您正在寻找一种方法来验证您的配置和网络可用性,而无需实际发送电子邮件。任何方式都是我需要的,因为没有有意义的虚拟电子邮件。

在我的开发人员同事的建议下,我想出了这个解决方案。一个小的帮助类,用法如下。我在发送电子邮件的服务的 OnStart 事件中使用了它。

注意:TCP 套接字内容的功劳归于 Peter A. Bromberg,网址为http://www.eggheadcafe.com/articles/20030316.asp,配置在这里向这些人读了一些东西:Access system.net settings from app.config在 C# 中以编程方式

帮手:

public static class SmtpHelper
{
    /// <summary>
    /// test the smtp connection by sending a HELO command
    /// </summary>
    /// <param name="config"></param>
    /// <returns></returns>
    public static bool TestConnection(Configuration config)
    {
        MailSettingsSectionGroup mailSettings = config.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;
        if (mailSettings == null)
        {
            throw new ConfigurationErrorsException("The system.net/mailSettings configuration section group could not be read.");
        }
        return TestConnection(mailSettings.Smtp.Network.Host, mailSettings.Smtp.Network.Port);
    }

    /// <summary>
    /// test the smtp connection by sending a HELO command
    /// </summary>
    /// <param name="smtpServerAddress"></param>
    /// <param name="port"></param>
    public static bool TestConnection(string smtpServerAddress, int port)
    {
        IPHostEntry hostEntry = Dns.GetHostEntry(smtpServerAddress);
        IPEndPoint endPoint = new IPEndPoint(hostEntry.AddressList[0], port);
        using (Socket tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
        {
            //try to connect and test the rsponse for code 220 = success
            tcpSocket.Connect(endPoint);
            if (!CheckResponse(tcpSocket, 220))
            {
                return false;
            }

            // send HELO and test the response for code 250 = proper response
            SendData(tcpSocket, string.Format("HELO {0}\r\n", Dns.GetHostName()));
            if (!CheckResponse(tcpSocket, 250))
            {
                return false;
            }

            // if we got here it's that we can connect to the smtp server
            return true;
        }
    }

    private static void SendData(Socket socket, string data)
    {
        byte[] dataArray = Encoding.ASCII.GetBytes(data);
        socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None);
    }

    private static bool CheckResponse(Socket socket, 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.ASCII.GetString(responseArray);
        int responseCode = Convert.ToInt32(responseData.Substring(0, 3));
        if (responseCode == expectedCode)
        {
            return true;
        }
        return false;
    }
}

用法:

if (!SmtpHelper.TestConnection(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)))
{
    throw new ApplicationException("The smtp connection test failed");
}
于 2010-05-18T20:29:04.893 回答
8

我认为这是异常处理将是首选解决方案的情况。在你尝试之前你真的不知道它会起作用,失败是一个例外。

编辑:

您需要处理 SmtpException。这有一个 StatusCode 属性,它是一个枚举,它会告诉您 Send() 失败的原因。

于 2008-12-16T21:16:49.643 回答
2

您可以尝试发送 HELO 命令来测试服务器是否处于活动状态并在发送电子邮件之前运行。如果您想检查用户是否存在,您可以尝试使用 VRFY 命令,但由于安全原因,这通常在 SMTP 服务器上被禁用。进一步阅读: http ://the-welters.com/professional/smtp.html 希望这会有所帮助。

于 2008-12-16T21:28:00.773 回答
2

捕获 SmtpException 异常,它会告诉您是否因为无法连接到服务器而失败。

如果您想在任何尝试之前检查是否可以打开与服务器的连接,请使用 TcpClient 并捕获 SocketExceptions。虽然我认为这样做与从 Smtp.Send 中捕获问题相比没有任何好处。

于 2008-12-16T21:30:16.650 回答
-1
    private bool isValidSMTP(string hostName)
    {
        bool hostAvailable= false;
        try
        {
            TcpClient smtpTestClient = new TcpClient();
            smtpTestClient.Connect(hostName, 25);
            if (smtpTestClient.Connected)//connection is established
            {
                NetworkStream netStream = smtpTestClient.GetStream();
                StreamReader sReader = new StreamReader(netStream);
                if (sReader.ReadLine().Contains("220"))//host is available for communication
                {
                    hostAvailable= true;
                }
                smtpTestClient.Close();
            }
        }
        catch
        {
          //some action like writing to error log
        }
        return hostAvailable;
    }
于 2017-11-14T04:54:36.560 回答
-2

我也有这个需求。

这是我创建的库(它发送HELO并检查 200、220 或 250):

using SMTPConnectionTest;

if (SMTPConnection.Ok("myhost", 25))
{
   // Ready to go
}

if (SMTPConnectionTester.Ok()) // Reads settings from <smtp> in .config
{
    // Ready to go
}
于 2015-06-30T14:59:14.077 回答