I created a New Event Emailer.
this takes some fun events from a nice SQL query and creates a little HTML message and sends it to all the subscribers of events, when new event types are added we need to be able to tell them that they need to add the events to their subscription if they want to be notified of them.
One issue is that if we send too many emails to the same domain in a short period of time we will get black listed from that domain, and that's not good.
so I coded this emailer to take the list of emails and email 10 at a time with a 6 second delay in the middle.
Is there anything that is inefficient or some edge case that I am missing?
class NewEventMailer //: IDisposable
{
#if DEBUG
private static string _messageHeader = Resources.NewEventsEmailer_Development.HeaderMessage;
private static string _logFileLocation = Resources.DebugStrings.LogFileLocation;
private static string _SmtpServer = Resources.DebugStrings.SmtpServer;
private static string _SmtpServerPort = Resources.DebugStrings.SmtpServerPort;
private static string _emailSender = Resources.DebugStrings.EmailSender;
private static string _newEventSubjectLine = Resources.NewEventsEmailer_Development.NewEventSubjectLine;
private static string _defaultRecipient = Resources.NewEventsEmailer_Development.DefaultRecipient;
private static string _NewEventSubjectLine = Resources.NewEventsEmailer_Development.NewEventSubjectLine;
#else
private static string _messageHeader = Resources.NewEventsEmailer_Production.HeaderMessage;
private static string _logFileLocation = Resources.ProductionStrings.LogFileLocation;
private static string _SmtpServer = Resources.ProductionStrings.SmtpServer;
private static string _SmtpServerPort = Resources.ProductionStrings.SmtpServerPort;
private static string _emailSender = Resources.ProductionStrings.EmailSender;
private static string newEventSubjectLine = Resources.NewEventsEmailer_Production.NewEventSubjectLine;
private static string _NewEventSubjectLine = Resources.NewEventsEmailer_Production.NewEventSubjectLine;
//Default Email set in Development Resource.
private static string _defaultRecipient = Resources.NewEventsEmailer_Development.DefaultRecipient;
#endif
private string _eventMailMessage;
private List<string> _addresses;
public NewEventMailer(DataTable newEventTable, List<string> addresses)
{
this._addresses = addresses;
_eventMailMessage = EventMessage(newEventTable);
}
public string EventMessage(DataTable eventTable)
{
StringBuilder newMessage = new StringBuilder();
newMessage.Append("<table style='text-align:left; width:750px'><tr><th colspan='2' style='text-align:left;'>" + _messageHeader + "</th></tr>");
newMessage.Append("<tr><td style='border-bottom:groove; border-bottom-color:silver; font-size:x-large'>Event Name</td><td style='border-bottom:groove; border-bottom-color:silver; font-size:x-large'>Event Group</td></tr>");
foreach (DataRow row in eventTable.Rows)
{
newMessage.Append("<tr><td>" + row.Field<string>("EventName") + "</td><td>" + row.Field<string>("EventGroup") + "</td></tr>");
}
newMessage.Append("</table>");
return newMessage.ToString();
}
public void SendNewEventEmail()
{
int emailCounter = 0;
MailMessage emailMessage = GetNewMailMessage(); //First Mail Message
bool emailSent = false;
foreach (var address in _addresses)
{
emailSent = false;
var bccAddress = new MailAddress(address);
emailMessage.Bcc.Add(bccAddress);
emailCounter++;
if (emailCounter % 10 == 0)
{
using (SmtpClient mailClient = new SmtpClient(_SmtpServer, Convert.ToInt32(_SmtpServerPort)))
{
mailClient.Send(emailMessage);
Thread.Sleep(6000);
emailSent = true;
emailMessage = GetNewMailMessage();
}
}
}
if (emailSent == false)
{
using (SmtpClient mailClient = new SmtpClient(_SmtpServer, Convert.ToInt32(_SmtpServerPort)))
{
mailClient.Send(emailMessage);
}
}
}
public MailMessage GetNewMailMessage()
{
MailMessage emailMessage = new MailMessage(_emailSender, _defaultRecipient);
emailMessage.IsBodyHtml = true;
emailMessage.Body = _eventMailMessage;
emailMessage.Subject = _NewEventSubjectLine;
return emailMessage;
}
}
And here is the Method in the main program class that calls everything into play
public static void SendNewEventsEmails()
{
List<string> Addresses = new List<string>();
//Get Email Addresses
using (SqlConnection emailConn = new SqlConnection(Resources.DebugStrings.AttorneyEventCS))
using (SqlCommand emails = new SqlCommand("[SQL_SELECT_STATEMENT_FOR_EMAIL_ADDRESSES]", emailConn))
using (SqlDataAdapter emailsToData = new SqlDataAdapter())
using (DataTable emailsTable = new DataTable())
{
emailConn.Open();
emailsTable.Load(emails.ExecuteReader());
foreach (DataRow email in emailsTable.Rows)
{
Addresses.Add(email.Field<string>("EmailTo"));
}
}
//Send Email
using (SqlConnection conn = new SqlConnection(Resources.ProductionStrings.AttorneyEventCS))
using (SqlCommand newEventSproc = new SqlCommand()
{
CommandType = CommandType.StoredProcedure
, CommandText = "[SPROC_Name]"
, Connection = conn
})
{
conn.Open();
newEventSproc.Parameters.AddWithValue("@DaysPast", 30);
DataTable newEventsTable = new DataTable();
newEventsTable.Load(newEventSproc.ExecuteReader());
NewEventMailer newEventMailer = new NewEventMailer(newEventsTable, Addresses);
newEventMailer.SendNewEventEmail();
}
}
Production has new events in the last 30 days, hence the reason for the production connection string, I still have some testing to do to get this to only email on the 1st of the month. but it works the way I intended it to.