Это связано с вопросом, который я недавно задал на как отправить электронное письмо.
Мой новый связанный с этим вопрос заключается в следующем ... что, если пользователь моего приложения находится за брандмауэром или по какой-то другой причине, по которой строка client.Send (mail) не будет работать ...
После строк:
SmtpClient client = new SmtpClient("mysmtpserver.com", myportID);
client.Credentials = new System.Net.NetworkCredential("myusername.com", "mypassword");
Могу ли я что-нибудь сделать для тестирования клиента перед отправкой?
Я подумал о том, чтобы поместить это в цикл try / catch, но я бы предпочел провести тест, а затем вывести диалоговое окно с сообщением: не могу получить доступ к smtp или что-то в этом роде.
(Я предполагаю, что ни я, ни потенциально мой пользователь приложения не имеют возможности изменять настройки своего брандмауэра. Например ... они устанавливают приложение на работе и не контролируют свой Интернет на работе)
-Адина





Я думаю, что это тот случай, когда обработка исключений была бы предпочтительным решением. Вы действительно не знаете, что это сработает, пока не попробуете, и неудача - исключение.
Редактировать:
Вы захотите обработать SmtpException. У него есть свойство StatusCode, которое представляет собой перечисление, которое расскажет вам, почему не удалось выполнить Send ().
Я пытаюсь реализовать отправителя транзакционной электронной почты, и исключения нельзя использовать, потому что тест должен быть в другой части потока транзакции.
Вы можете попробовать отправить команду HELO, чтобы проверить, активен ли сервер и работает ли он, прежде чем отправлять электронное письмо. Если вы хотите проверить, существует ли пользователь, вы можете попробовать с помощью команды VRFY, но она часто отключена на SMTP-серверах из соображений безопасности. Дальнейшее чтение: http://the-welters.com/professional/smtp.html Надеюсь это поможет.
Поймайте исключение SmtpException, оно сообщит вам, не удалось ли оно из-за того, что вы не смогли подключиться к серверу.
Если вы хотите проверить, можете ли вы открыть соединение с сервером перед любой попыткой, используйте TcpClient и перехватите SocketExceptions. Хотя я не вижу в этом никакой пользы, чем просто отловить проблемы из Smtp.Send.
Ух, потому что, возможно, это загрузка вашего приложения, или вам нужно проверить подключение к вашему SMTP-серверу на основе опроса, и у вас еще нет электронной почты для отправки, и вы хотите проверить / убедиться, что ваша способность отправлять, когда вы это сделаете - вот почему.
Я думаю, что если вы хотите протестировать SMTP, это значит, что вы ищете способ проверить свою конфигурацию и доступность сети без фактической отправки электронной почты. В любом случае это то, что мне было нужно, поскольку не было пустых писем, которые имели бы смысл.
По предложению моего коллеги-разработчика я придумал это решение. Небольшой вспомогательный класс, использование которого приведено ниже. Я использовал его в событии OnStart службы, рассылающей электронные письма.
Примечание: заслуга за содержимое сокетов TCP принадлежит Питеру А. Бромбергу в http://www.eggheadcafe.com/articles/20030316.asp, а конфигурация читается ребятам здесь: Программный доступ к настройкам system.net из 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");
}
Отличное решение. Работает как шарм и позволяет мне легко переключаться между SMTP-серверами, если первый по какой-то причине недоступен.
Отлично. Я изменил Dns.GetHostEntry на Dns.GetHostAddresses, который должен быть быстрее и не даст сбой, если IP-адрес передан и обратная запись DNS не найдена.
Обратите внимание, что этот код случайно не сработает из-за использования socket.Available.
Есть ли еще код, не показанный здесь? Компилятор C# не знает, что такое Конфигурация. Я предполагаю, что это часть класса конфигурации в приложении. Что мне нужно сделать, чтобы исправить ошибку компиляции? Я использую Visual Studio 2015.
@octopusgrabbus Вам необходимо добавить в свой класс ссылочный System.Configuration и оператор using System.Configuration;. Также необходимы статусы using для System, System.Net, System.Net.Configuration, System.Net.Sockets, System.Text.
Как указал @Jan Zahradník в моем случае, я использую IPAddress.TryParse(), чтобы определить, является ли данная строка IP-адресом или именем хоста, и, следуя случаю, я использую Dns.GetHostEntry или Dns.GetHostAddresses в функции.
У меня тоже была такая потребность.
Вот созданная мной библиотека (он отправляет 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
}
ссылка больше не существует
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;
}
но не правда ли, что могут быть другие причины, по которым исключение перехвачено ... и я знаю об этой конкретной возможности, и хотел бы обработать ее как ее собственный случай ... имеет ли это смысл?