2008-12-16 8 views
19

Ceci est lié à une question que j'ai posée l'autre jour sur how to send email.Puis-je tester SmtpClient avant d'appeler client.Send()?

Ma nouvelle question relative est ce ... si l'utilisateur de mon application est derrière un pare-feu ou d'une autre raison pour laquelle la ligne client.Send (courrier) ne fonctionnera pas ...

Après les lignes:

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

Y at-il quelque chose que je peux faire pour tester le client avant d'essayer d'envoyer? J'ai pensé à mettre ceci dans une boucle try/catch, mais je préfère faire un test et ouvrir une boîte de dialogue disant: ne peut pas accéder à smtp ou quelque chose comme ça.

(Je présume que ni moi, ni mon utilisateur de l'application potentiellement, n'a la possibilité d'ajuster leurs paramètres de pare-feu, par exemple ... ils installent l'application au travail et n'ont pas de contrôle sur leur internet au travail)

-Adeena

Répondre

9

Je pense que c'est un cas où la gestion des exceptions serait la meilleure solution. Vous ne savez vraiment pas que cela fonctionnera jusqu'à ce que vous essayiez, et l'échec est une exception.

Edit:

Vous voulez gérer SmtpException. Cela a une propriété StatusCode, qui est une énumération qui vous indiquera pourquoi le Send() a échoué.

+0

mais est-il pas vrai qu'il pourrait y avoir d'autres raisons pour lesquelles une exception est pris ... et je connais cette possibilité spécifique, et je voudrais la gérer comme c'est le cas ... est-ce logique? – adeena

+0

J'essaye d'implémenter l'expéditeur d'email transactionnel et les exceptions ne peuvent pas être utilisées parce que le test devrait être dans la partie différente du flux de transaction. –

1

Vous pouvez essayer d'envoyer une commande HELO pour tester si le serveur est actif et en cours d'exécution avant d'envoyer l'e-mail. Si vous voulez vérifier si l'utilisateur existe, vous pouvez essayer avec la commande VRFY, mais cela est souvent désactivé sur les serveurs SMTP pour des raisons de sécurité. Plus de lecture: http://the-welters.com/professional/smtp.html Espérons que cela aide.

2

Attraper l'exception SmtpException, il vous dira si elle a échoué parce que vous ne pouviez pas vous connecter au serveur.

Si vous voulez vérifier si vous pouvez ouvrir une connexion au serveur avant toute tentative, utilisez TcpClient et récupérez SocketExceptions. Bien que je ne vois aucun avantage à le faire vs juste attraper des problèmes de Smtp.Send.

+0

Euh, parce que c'est peut-être le chargement de votre application, ou vous devez vérifier la connectivité à votre serveur SMTP dans une base d'interrogation, et vous n'avez pas encore d'e-mail à envoyer et vous voulez tester/garantir votre capacité à envoyer , quand vous faites - ce serait pourquoi. – vapcguy

36

Je pense que si vous cherchez à tester le SMTP, c'est que vous cherchez un moyen de valider votre configuration et la disponibilité du réseau sans envoyer un email. De toute façon c'est ce dont j'avais besoin, car il n'y avait pas de courriel factice qui aurait du sens.

Avec la suggestion de mon collègue développeur j'ai trouvé cette solution. Une petite classe d'aide avec l'utilisation ci-dessous. Je l'ai utilisé lors de l'événement OnStart d'un service qui envoie des emails.

Note: le crédit pour le socket TCP va à Peter A.Bromberg à http://www.eggheadcafe.com/articles/20030316.asp et la config lire des choses les gars ici: Access system.net settings from app.config programmatically in C#

Aide:

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

Utilisation:

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

Excellente solution. Fonctionne comme un charme et me permet de basculer facilement entre les serveurs SMTP si le premier n'est pas disponible pour une raison quelconque. – Catch22

+1

Génial. J'ai changé 'Dns.GetHostEntry' en' Dns.GetHostAddresses' qui devrait être plus rapide et n'échouera pas si l'adresse IP est passée et aucune entrée inverse de DNS trouvée. –

+1

Notez que ce code échouera aléatoirement en raison de l'utilisation de 'socket.Available'. – usr

-1

J'ai aussi eu ce besoin.

Here's the library I made (il envoyer un HELO et des chèques pour un 200, 220 ou 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; 
    }