2008-12-16 7 views
19

Esto está relacionado con una pregunta que hice el otro día en how to send email.¿Puedo probar SmtpClient antes de llamar a client.Send()?

Mi nuevo, pregunta relacionada es esto ... ¿y si el usuario de mi solicitud está detrás de un cortafuegos o alguna otra razón por la línea client.Send (mail) no va a funcionar ...

Después las líneas:

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

¿hay algo que pueda hacer para probar el cliente antes de intentar enviar?

Pensé en poner esto en un ciclo de prueba/captura, pero prefiero hacer una prueba y luego abrir un cuadro de diálogo que dice: no puedo acceder a smtp o algo así.

(Estoy suponiendo que ni yo ni mi usuario de la aplicación, tengo la capacidad de ajustar la configuración de su firewall. Por ejemplo ... instalan la aplicación en el trabajo y no tienen control sobre su internet en el trabajo)

-Adeena

Respuesta

9

creo que este es un caso en el manejo de excepciones sería la solución preferida. Realmente no sabes que funcionará hasta que lo intentes, y el fracaso es una excepción.

Editar:

Usted querrá manejar SmtpException. Tiene una propiedad StatusCode, que es una enumeración que le indicará por qué no se pudo enviar Send().

+0

pero no es cierto que podría haber otras razones por las cuales se detecta una excepción ... y conozco esta posibilidad específica, y me gustaría manejarla como es su caso ... ¿tiene sentido? – adeena

+0

Estoy tratando de implementar el remitente de correo electrónico transaccional y las excepciones no se pueden usar porque la prueba debe estar en una parte diferente del flujo de transacción. –

1

Puede intentar enviar un comando HELO para comprobar si el servidor está activo y ejecutándose antes de enviar el correo electrónico. Si desea verificar si el usuario existe, puede intentarlo con el comando VRFY, pero esto a menudo está deshabilitado en los servidores SMTP debido a razones de seguridad. Lectura adicional: http://the-welters.com/professional/smtp.html Espero que esto ayude.

2

Capture la excepción SmtpException, le dirá si falló porque no pudo conectarse al servidor.

Si desea comprobar si puede abrir una conexión con el servidor antes de cualquier intento, utilice TcpClient y capture SocketExceptions. Aunque no veo ningún beneficio al hacer esto frente a los problemas de Smtp.Send.

+0

Uh, porque tal vez está cargando su aplicación, o necesita verificar la conectividad a su servidor SMTP en una base de votación, y aún no tiene un correo electrónico para enviar y desea probar/asegurar su capacidad para enviar cuando lo hagas, esa sería la razón. – vapcguy

36

Creo que si buscas probar el SMTP es que estás buscando una forma de validar tu configuración y disponibilidad de red sin enviar un correo electrónico. De cualquier forma eso es lo que necesitaba ya que no había ningún correo electrónico falso que tuviera sentido.

Con la sugerencia de mi compañero desarrollador, se me ocurrió esta solución. Una pequeña clase de ayuda con el uso a continuación. Lo usé en el evento OnStart de un servicio que envía correos electrónicos.

Nota: el crédito para el socket TCP es para Peter A.Bromberg en http://www.eggheadcafe.com/articles/20030316.asp y la configuración leen cosas para los chicos aquí: Access system.net settings from app.config programmatically in C#

Ayudante:

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; 
    } 
} 

Uso:

if (!SmtpHelper.TestConnection(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None))) 
{ 
    throw new ApplicationException("The smtp connection test failed"); 
} 
+1

Gran solución. Funciona como un encanto y me permite cambiar fácilmente entre servidores SMTP si el primero no está disponible por alguna razón. – Catch22

+1

Genial. Cambié 'Dns.GetHostEntry' a' Dns.GetHostAddresses' que debería ser más rápido y no fallará si se pasa la dirección IP y no se encuentra ninguna entrada dns inversa. –

+1

Tenga en cuenta que este código fallará aleatoriamente debido al uso de 'socket.Available'. – usr

-1

También tuve esta necesidad.

Here's the library I made (que enviar un HELO y comprueba si hay un 200, 220 o 250):

using SMTPConnectionTest; 

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

if (SMTPConnectionTester.Ok()) // Reads settings from <smtp> in .config 
{ 
    // Ready to go 
} 
-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; 
    } 
Cuestiones relacionadas