2008-12-16 14 views
19

Dies steht im Zusammenhang mit einer Frage, die ich neulich am how to send email gestellt habe.Kann ich SmtpClient vor dem Aufruf von client.Send() testen?

Meine neue, verwandte Frage ist ... was ist, wenn der Benutzer meiner Anwendung ist hinter einer Firewall oder einem anderen Grund, warum die Linie client.Send (Mail) wird nicht funktionieren ...

Nach die Zeilen:

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

Gibt es etwas, was ich tun kann, um den Client zu testen, bevor ich versuche, zu senden?

Ich dachte darüber nach, dies in eine try/catch-Schleife zu setzen, aber ich würde lieber einen Test machen und dann einen Dialog öffnen, der sagt: kann nicht auf smtp oder so etwas zugreifen.

(Ich gehe davon aus, dass weder ich, noch potenziell meine Anwendung Benutzer, ihre Firewall-Einstellungen anpassen können. Zum Beispiel ... sie installieren die App bei der Arbeit und haben keine Kontrolle über ihre Internet bei der Arbeit

)

-Adeena

Antwort

9

ich denke, dies ist ein Fall, wo die Ausnahmebehandlung die bevorzugte Lösung wäre. Sie wissen wirklich nicht, dass es funktioniert, bis Sie es versuchen, und Fehler ist eine Ausnahme.

Edit:

Sie wollen SmtpException behandeln. Dies hat eine StatusCode -Eigenschaft, die eine Aufzählung ist, die Ihnen sagen wird, warum Send() fehlgeschlagen ist.

+0

aber ist es, dass es nicht wahr andere Gründe geben könnte, warum eine Ausnahme gefangen ... und ich kenne diese eine spezifische Möglichkeit und würde gerne damit umgehen, da es ein eigener Fall ist ... macht das Sinn? – adeena

+0

Ich versuche, Transaktions-E-Mail-Absender zu implementieren, und Ausnahmen können nicht verwendet werden, da der Test sich in einem anderen Teil des Transaktionsflusses befinden sollte. –

1

Sie könnten versuchen, einen HELO-Befehl zu senden, um zu testen, ob der Server aktiv ist und vorher ausgeführt wird, um die E-Mail zu senden. Wenn Sie überprüfen möchten, ob der Benutzer existiert, können Sie mit dem Befehl VRFY versuchen, aber das ist oft auf SMTP-Servern aus Sicherheitsgründen deaktiviert. Weiterführende Literatur: http://the-welters.com/professional/smtp.html Hoffe, das hilft.

2

Fangen Sie die SmtpException-Ausnahme ab, es wird Ihnen sagen, wenn es fehlgeschlagen ist, weil Sie keine Verbindung zum Server herstellen konnten.

Wenn Sie überprüfen möchten, ob Sie vor jedem Versuch eine Verbindung zum Server herstellen können, verwenden Sie TcpClient und fangen Sie SocketExceptions ab. Allerdings sehe ich keinen Vorteil, dies zu tun vs nur Probleme von Smtp.Send zu fangen.

+0

Uh, weil vielleicht Ihre App geladen ist oder Sie die Verbindung zu Ihrem SMTP-Server abfragen müssen, und Sie haben noch keine E-Mail zu senden, und Sie möchten Ihre Fähigkeit zum Senden testen/sicherstellen wenn du es tust - das wäre der Grund. – vapcguy

36

Ich denke, wenn Sie versuchen, das SMTP zu testen, dass Sie nach einer Möglichkeit suchen, Ihre Konfiguration und Netzwerkverfügbarkeit zu überprüfen, ohne tatsächlich eine E-Mail zu senden. Jedenfalls brauchte ich das, weil es keine Dummy-E-Mail gab, die Sinn machen würde.

Mit dem Vorschlag meines Kollegen Entwickler kam ich auf diese Lösung. Eine kleine Helferklasse mit der folgenden Verwendung. Ich habe es beim OnStart-Ereignis eines Dienstes verwendet, der E-Mails versendet.

Hinweis: Der Kredit für die TCP-Socket Zeug geht an Peter A.Bromberg bei http://www.eggheadcafe.com/articles/20030316.asp und die Config lesen Zeug an die Jungs hier: Access system.net settings from app.config programmatically in C#

Helper:

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

Verbrauch:

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

Große Lösung. Funktioniert wie ein Zauber und erlaubt mir, leicht zwischen SMTP-Servern zu wechseln, wenn der erste aus irgendeinem Grund nicht verfügbar ist. – Catch22

+1

Großartig. Ich habe "Dns.GetHostEntry" in "Dns.GetHostAddresses" geändert, was schneller sein sollte und nicht fehlschlägt, wenn die IP-Adresse übergeben wird und kein umgekehrter DNS-Eintrag gefunden wurde. –

+1

Beachten Sie, dass dieser Code aufgrund der Verwendung von 'socket.Available' zufällig fehlschlägt. – usr

-1

Ich hatte auch dieses Bedürfnis.

Here's the library I made (eine HELO und Kontrollen für eine 200, 220 oder 250 senden):

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