Как проверить, было ли доставлено письмо с использованием C# MailMessage
Я использую приведенный ниже код для отправки электронной почты, он работает нормально большую часть времени, и во время теста мы обнаружили, что иногда он не доставляет электронную почту. Как я могу изменить этот код, чтобы проверить состояние доставки электронной почты или шрифта любой другой сбой.
public static void SendEmail(string to, string subject, string message, bool isHtml)
{
try
{
var mail = new MailMessage();
// Set the to and from addresses.
// The from address must be your GMail account
mail.From = new MailAddress("noreplyXYZ@gmail.com");
mail.To.Add(new MailAddress(to));
// Define the message
mail.Subject = subject;
mail.IsBodyHtml = isHtml;
mail.Body = message;
// Create a new Smpt Client using Google's servers
var mailclient = new SmtpClient();
mailclient.Host = "smtp.gmail.com";//ForGmail
mailclient.Port = 587; //ForGmail
// This is the critical part, you must enable SSL
mailclient.EnableSsl = true;//ForGmail
//mailclient.EnableSsl = false;
mailclient.UseDefaultCredentials = true;
// Specify your authentication details
mailclient.Credentials = new System.Net.NetworkCredential("noreplyXYZ@gmail.com", "xxxx123");//ForGmail
mailclient.Send(mail);
mailclient.Dispose();
}
catch (Exception ex)
{
throw ex;
}
}
Я знаю, что SMTP отвечает за отправку электронной почты, и статус доставки невозможен, но это способ проверить состояние доставки электронной почты.
ОБНОВЛЕННЫЙ КОД (это правильно)
public static void SendEmail(string to, string subject, string message, bool isHtml)
{
var mail = new MailMessage();
// Set the to and from addresses.
// The from address must be your GMail account
mail.From = new MailAddress("noreplyXYZ@gmail.com");
mail.To.Add(new MailAddress(to));
// Define the message
mail.Subject = subject;
mail.IsBodyHtml = isHtml;
mail.Body = message;
// Create a new Smpt Client using Google's servers
var mailclient = new SmtpClient();
mailclient.Host = "smtp.gmail.com";//ForGmail
mailclient.Port = 587; //ForGmail
mailclient.EnableSsl = true;//ForGmail
//mailclient.EnableSsl = false;
mailclient.UseDefaultCredentials = true;
// Specify your authentication details
mailclient.Credentials = new System.Net.NetworkCredential("noreplyXYZ@gmail.com", "xxxx123");//ForGmail
mailclient.Send(mail);
mailclient.Dispose();
try
{
mailclient.Send(mail);
mailclient.Dispose();
}
catch (SmtpFailedRecipientsException ex)
{
for (int i = 0; i < ex.InnerExceptions.Length; i++)
{
SmtpStatusCode status = ex.InnerExceptions[i].StatusCode;
if (status == SmtpStatusCode.MailboxBusy ||status == SmtpStatusCode.MailboxUnavailable)
{
// Console.WriteLine("Delivery failed - retrying in 5 seconds.");
System.Threading.Thread.Sleep(5000);
mailclient.Send(mail);
}
else
{
// Console.WriteLine("Failed to deliver message to {0}", ex.InnerExceptions[i].FailedRecipient);
throw ex;
}
}
}
catch (Exception ex)
{
// Console.WriteLine("Exception caught in RetryIfBusy(): {0}",ex.ToString());
throw ex;
}
finally
{
mailclient.Dispose();
}
}
2 ответа
Ну, у вас есть все тело кода, завернутого в try
блок с пустым catch
блок. Таким образом, если сообщение не удастся отправить по какой-либо причине, вы не будете знать, потому что ваша функция просто вернется.
Если вы посмотрите на документацию MSDN для SmtpClient.Send
вы увидите, что есть ряд различных исключений, которые он может генерировать по разным причинам. Пара интересных:
SmtpException
SmtpFailedRecipientsException
Пару заметок после вашего обновления:
Вы, вероятно, не хотите делать это:
mailclient.Send(mail);
mailclient.Dispose();
try
{
mailclient.Send(mail);
mailclient.Dispose();
}
Вы избавляетесь mailclient
прежде чем пытаться использовать его снова.
using
MailMessage
а также SmtpClient
оба реализуют IDisposable
так что было бы лучше (и проще всего) поместить их в using
блок:
using (var mail = new MailMessage())
using (var mailclient = new SmtpClient())
{
// ...
}
Тогда вам не придется беспокоиться о звонке Dispose()
в вашем finally
блоки (они могут вам вообще не понадобиться).
throw
Вы, вероятно, знаете, но нет никакого смысла в:
catch (Exception ex)
{
throw ex;
}
foreach
for (int i = 0; i < ex.InnerExceptions.Length; i++)
{
SmtpStatusCode status = ex.InnerExceptions[i].StatusCode;
// ...
}
Может быть переписан как:
foreach (var innerEx in ex.InnerExceptions)
{
var status = innerEx.StatusCode;
}
Thread.Sleep()
Если этот код предназначен для пользователя, вы, вероятно, на самом деле не хотите этого делать, так как это приведет к зависанию страницы в течение 5 секунд в ожидании отправки. На мой взгляд, вы все равно не должны обрабатывать отправку почты непосредственно в коде веб-страницы, вы должны поставить ее в очередь для отправки в фоновом режиме. Но это совсем другая проблема.
Несколько вещей, которые помогут сделать вас лучшим программистом C#.
Похоже, вы спрашиваете, есть ли способ в режиме реального времени проверить, получил ли ваш пользователь сообщение. Если это так, я бы порекомендовал вам не идти по этому пути. Хотя в большинстве случаев доставка электронной почты кажется мгновенной, ее можно отложить на любой промежуток времени до доставки в почтовый ящик получателя.
Я предлагаю вам перейти по следующим ссылкам на форуме asp.net:
SMTP-сервер и электронная почта FAQ
Уведомление о доставке не работает при отправке писем
Лучшая практика для осуществления проверки, если электронное письмо отправлено
Примечание. Не существует надежного способа узнать, действительно ли сообщение было доставлено.
Есть еще одна тема, которую вы уже просили:
Как проверить, что MailMessage был доставлен в.NET?
ASP.NET MVC Как определить, не достигла ли электронная почта получателя