I want to send an email just once per day. There is one button and any user can click that button. The email must not be sent twice. When the first user clicks the button, the email is sent. If some other user clicks the button, the email will not be sent again.
This is how I implemented, and it's working. There are some cases, once a month, when 2 email are sent, but I don't know why.
I am sure that there is more elegant way to resolve this problem. Please share with me your ideas.
protected void Send(string email, String allRecipients, String subject, String body)
{
//Be sure that email is send just once:
//Lock an object, and if its already locked just continue,
if (Monitor.TryEnter(syncLock))
{
try
{
//Send email only if is not send already.
//Check in DB if is send.
//IsSend function return true if email is send already, else false.
if (!IsSent())
{
SendEmails(email, allRecipients, subject, body);
}
}
finally
{
Monitor.Exit(syncLock);
}
}
}
Function that sends email:
public static void SendEmails(string email, String allRecipients, String subject, String body)
{
//Flag if email is sent or not:
Boolean isEmailSend = false;
SmtpClient client = new SmtpClient();
//Message:
MailMessage message = new MailMessage(email, allRecipients, subject, body);
try
{
isEmailSend = true;
client.Send(message);
}
catch (SmtpException e)
{
isEmailSend = false;
throw new SmtpException(e.ToString());
}
catch (TimeoutException e)
{
//Problem: Not sure if is email send or not:
isEmailSend = false;
throw new TimeoutException("TIME OUT:" + e.ToString());
}
catch (Exception e)
{
//Problem: Not sure if is email send or not:
isEmailSend = false;
throw new Exception(e.ToString());
}
finally
{
if (isEmailSend)
{
//Update DB.
//Set that email is send.
//This update in DB that email for current day is send already.
SetAsSend();
}
}
}
IsSent
function
//Check if meeting is sent today.
public static bool IsSent()
{
string connectionString = ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString;
bool isSent = false;
const string CHECK_IF_SEND = "SELECT TOP 1 IsSent FROM MessageTable m WHERE m.date =@todayDate ";
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(CHECK_IF_SEND, conn);
command.Parameters.Add("@todayDate", DbType.Date).Value = DateTime.Today;
try
{
conn.Open();
Object result = command.ExecuteScalar();
if (result != null)
{
isSent = (bool)result;
}
}
finally
{
conn.Close();
conn.Dispose();
}
return isSent;
}
Close()
andDispose()
your database connection object. JustDispose()
will do. Better yet, wrap it in ausing
construct. Also, same goes for the command as it implementsIDisposable
as well. \$\endgroup\$