Sending Automated Emails asynchronously using a C# Windows Service in conjunction with Database Email records PART – II

This tutorial is in continuation to the creation of a C# Windows Service to send Automated Emails asynchronously. Kindly go through the following link to get started with the PART – I.

================================================================================================

Sending Automated Emails asynchronously using a C# Windows Service in conjunction with Database Email records PART – I

================================================================================================

NOTE :-
  1. This part of the tutorial is especially focused on the Windows Service creation, configuration and installation. The concepts (precisely the database and class library) used in this part is already created and explained in the Part 1 of the tutorial.
  2. Apart from the continuation from Part –1, this Part can actually be implemented separately according to the requirement. At the same time, this part of the tutorial can be implemented with variety of concepts like XML, EF, LINQ etc. So it is typically based on the requirement to make different pieces fall in place.

In this part of the tutorial, we first create a Windows Service Project, then implement a Service called – ‘BirthdayEmailService’. Then we add a reference to our previously created Class Library – ‘EmailComponent’. We code BirthdayEmailService using Timer to perform the email sending task for every hour. Then we incorporate the Installer classes for the purpose of installation. Finally a Setup and Deployment Project is created for the Service. Finally the complete Solution is build and the exe file is generated which is ready enough to get installed.

IMPORTANT – The logic in the using the Timer is to send emails in particular intervals of time. The timer interval is set to 60mins, and it is set to that value solely for demonstration purpose. According to the written logic, emails will be send only for the first time elapsed event of a particular date, so that the repetition of sending emails to the same customers can be avoided. Always remember, logic in the service Time Event can be modified according to ones requirement.

================================================================================================

BirthdayEmailService Project

This section narrates how to create a Windows Project. It also discuss how to prepare the project according to our requirement (say adding references etc).

================================================================================================

Let’s get started with the creation of Windows Service.

  1. Open VS 2010
  2. File -> New -> Project
  3. Select ‘Visual C#’ -> Windows -> Windows Service Template -> Give Name ‘BirthdayEmailSevice’
  4. Delete the default Service1.cs

To access Database i.e., CustomerDB, we include a app.config file which in this case hold the data corresponding to the database connectivity ( like connection string etc).

To add app.config file -

  1. Right click ‘BirthdayEmailService’ in the solution explorer –> Select ‘Add New Item’.
  2. Select ‘Visual C#’ -> Select Application Configuration File Template -> Click ADD.

To make the ConfigurationManager ( which is used to access config file settings in the code), we add reference to System.Configuration.dll to the project (right click Project ‘BirthdayEmailService’ -> Select Add Reference -> from .Net tab, Select System.Configuaration -> click ADD).

Put the following code in the created app.config file –

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="CustomerDBConnectionString"
       connectionString="Data Source=RAMILU-PC\SQLEXPRESS;Initial Catalog=CustomerDB;Integrated Security=True;Pooling=False"
       providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

Now let’s add a Service to the project –

  1. Right Click ‘BirthdayEmailService’ in the Solution Explorer –> Select ‘Add New Item’.
  2. Select ‘Visual C# Items’ -> Select Windows Service Template -> Give name – ‘BirthdayEmailService.cs’.
  3. Click ADD.

To Code against the EmailComponent (which we created earlier), we got to add reference of it to our service.

  1. Right Click ‘References’ of BirthdayEmailService –> Select ‘Add Reference’.
  2. Select ‘Browse’ tab -> Navigate to the ‘EmaiComponent’ project folder -> Select the EmailComponent.dll in the bin/Debug folder of ‘EmailComponent’ project. (NOTE: Before adding the reference, build the EmailComponent Project so that it would be up to date.)
  3. Click OK.

One last thing which is left behind is to change the Entry point of the application -

  1. Open Program.cs of the newly created service.
  2. Replace the Main() function with the following one –
        static void Main()
        {
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
                                {
                                    new BirthdayEmailService()
                                };
                ServiceBase.Run(ServicesToRun);
        }

Now, Writing code to BirthdayEmailService.cs –

  1. Open BirthdayEmailService.cs in designer mode in VS 2010.
  2. Drag and drop an EventLog component and Timer component (Please do not add this Timer component, I am adding this component from C# – Update : 1/16/2012) from the ToolBox on to the designer.
  3. Change their names to eventLogEmail and scheduleTimer (check (2), please do not add Timer component, I am adding this from C# – Update : 1/16/2012).
  4. EventLog is used to log the activities of the service, and timer is used to make the service run at particular intervals of time.
  5. Right click anywhere in the designer surface -> Select -> View Code.

Write the following code –

  • Change the Settings/Properties as per your own settings. Especially the Network Credentials and Username.
  • In the code, we first get the email id’s (in DataSet) of all the customers who are celebrating their birthday on that particular day, then we iterate through the through the DataSet and call the SendEmailAsync() method of EmailComponent dll. SendEmailAsync() method then process asynchronously and sends back the result.
  • We set the From Email, To Email, subject, Message Body etc. properties in this routine and pass the same values to the EmailComponent dll for further processing.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Timers;
using System.Configuration;
using EmailComponent;

namespace BirthdayEmailService
{
    partial class BirthdayEmailService : ServiceBase
    {
        private Timer scheduleTimer = null;
        private DateTime lastRun;
        private bool flag;

        public BirthdayEmailService()
        {
            InitializeComponent();
            if (!System.Diagnostics.EventLog.SourceExists("EmailSource"))
            {
                System.Diagnostics.EventLog.CreateEventSource("EmailSource", "EmailLog");
            }
            eventLogEmail.Source = "EmailSource";
            eventLogEmail.Log = "EmailLog";

            scheduleTimer = new Timer();
            scheduleTimer.Interval = 1 * 5 * 60 * 1000;
            scheduleTimer.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);

        }

        protected override void OnStart(string[] args)
        {
            flag = true;
            lastRun = DateTime.Now;
            scheduleTimer.Start();
            eventLogEmail.WriteEntry("Started");
        }

        protected void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (flag == true)
            {
                ServiceEmailMethod();
                lastRun = DateTime.Now;
                flag = false;
            }
            else if (flag == false)
            {
                if (lastRun.Date < DateTime.Now.Date)
                {
                    ServiceEmailMethod();
                }
            }
        }

        private void ServiceEmailMethod()
        {
            eventLogEmail.WriteEntry("In Sending Email Method");

            EmailComponent.GetEmailIdsFromDB getEmails = new EmailComponent.GetEmailIdsFromDB();
            getEmails.connectionString = ConfigurationManager.ConnectionStrings["CustomerDBConnectionString"].ConnectionString;
            getEmails.storedProcName = "GetBirthdayBuddiesEmails";
            System.Data.DataSet ds = getEmails.GetMailIds();

            EmailComponent.Email email = new EmailComponent.Email();

            email.fromEmail = "example@gmail.com";
            email.fromName = "example Name";
            email.subject = "Birthday Wishes";
            email.smtpServer = "smtp.gmail.com";
            email.smtpCredentials = new System.Net.NetworkCredential("example@gmail.com", "example password");

            foreach (System.Data.DataRow dr in ds.Tables[0].Rows)
            {
                email.messageBody = "<h4>Hello " + dr["CustomerName"].ToString() + "</h4><br/><h3>We Wish you a very Happy" +
                                    "Birthday  to You!!! Have a bash...</h3><br/><h4>Thank you.</h4>";

                bool result = email.SendEmailAsync(dr["CustomerEmail"].ToString(), dr["CustomerName"].ToString());

                if (result == true)
                {
                    eventLogEmail.WriteEntry("Message Sent SUCCESS to - " + dr["CustomerEmail"].ToString() +
                                             " - " + dr["CustomerName"].ToString());
                }
                else
                {
                    eventLogEmail.WriteEntry("Message Sent FAILED to - " + dr["CustomerEmail"].ToString() +
                                             " - " + dr["CustomerName"].ToString());
                }

            }
        }

        protected override void OnStop()
        {
            scheduleTimer.Stop();
            eventLogEmail.WriteEntry("Stopped");
        }
        protected override void OnPause()
        {
            scheduleTimer.Stop();
            eventLogEmail.WriteEntry("Paused");
        }
        protected override void OnContinue()
        {
            scheduleTimer.Start(); ;
            eventLogEmail.WriteEntry("Continuing");
        }
        protected override void OnShutdown()
        {
            scheduleTimer.Stop();
            eventLogEmail.WriteEntry("ShutDowned");
        }
    }
}

To install the created Service – We need to add installers, to do that –

  1. Go to the Designer Pane of the Service (BirthdayEmailService) -> Right Click in the Designer Pane -> Select Add Installer.

Now in Design view for ProjectInstaller, Select serviceInstaller1.

  1. Set the ServiceName property to BirthdayEmailService. Set the StartType property to Automatic.
  2. Now Select -> serviceProcessInstaller1 -> set its Account property to LocalSystem. This will cause the service to be installed and to run on a local service account.

This completes the coding part of the Service. Now to install Service, we got to create setup project –

  1. Right Click Solution -> Add -> New Project
  2. Other Project Types -> Setup and Deployment -> Visual Studio Installer –> Select ‘Setup’ Project.
  3. Name – BirthdayEmailServiceSetup -> Click ADD.

To Add Project Output –

  1. Right Click -> BirthdayEmailServiceSetup (in solution explorer) -> Add -> Project Output
  2. Select Primary Output (along with Service name in the top DropDownList) -> click OK.

To Add Custom Actions –

  1. In Solution Explorer, right-click the setup project, Select View, and then click Custom Actions.
  2. In the Custom Actions editor, right-click the Custom Actions node and click Add Custom Action.
  3. In the opened Dialog, Double-click the Application Folder in the list to open it, select Primary Output from BirthdayEmailService(Active), and click OK.

The final Stage –

  1. Right Click the BirthdayEmailService Project in the solutions explorer, and select Set As Startup Project.
  2. Then build the BirthdayEmailService Project.
  3. Finally build the BirthdayEmailServiceSetup project too.

The complete Folder structure would be -

EmailService-FolderStructure

On successful build, Navigate to the physical location of the Setup Project (BirthdayEmailServiceSetup) to find the exe file in the Debug Folder. Take the EXE file and install it by double clicking it. On successful install, we can find the service in the Systems Services Window -

  1. Go to Control Panel –> Administrative Tools –> Services.

We can start the service by right clicking it and select start. Similarly, we can stop it, pause it and continue it. The starting action of the service is only required for initial time, later onwards on shutdown and re-start, service will be automatically started.

EmailService-Services

 

To find the EventLog Entries -

  1. Go to Control Panel –> Administrative Tools –> Event Viewer –> Applications and Services Logs.

There we can find our EmailLog –

EventViewer-1

EventLog logging Email Send Details – ***I tested the code with 5mins time interval.

EventLog-EventViewer1

Sample Email in the Inbox -

EmailService-Output

Disclaimer:

All coding and suggestions made in the above discussion is strictly in point of view of the author. It is neither mentioned any where nor even concluded that this is the only possible way to go with, as there will be always a chance for a new approach in achieving the same requirement (in context of programming). The above mentioned code is strictly written and explained for the sake of new comers to C# and ASP.NET world.

You may also like...

One Pingback/Trackback

  • ramiramilu

    I think it an be because of permissions issue for the user role which is trying to install the service. Also try to uninstall it and re-install it again.

  • ramiramilu

    You have check local machine logs and share more information.

  • qwerzxcxyz

    sir.. ..I have error in the code.. ..which I have ambiguity in BirthdayEmailService.BirthdayEmailService.scheduleTime and BirthdayEmailService.BirthdayEmailService.scheduleTime

  • qwerzxcxyz

    same issue for me sir rami.. ..but if i go to control panel to uninstall it .. ..It is not there

  • ramiramilu

    That means it is not installed properly, can you try by creating the entire project from scratch?

  • qwerzxcxyz

    Sir Rami
    another problem.. ..i already fix my recent issues.. .but now if i start the service i don’t received message.. can you help me with this issue?

  • qwerzxcxyz

    Another thing sir rami.. ..I’m not receiving messages from the service.. ..which I have already replace all the detail that should be replaced.

  • ramiramilu

    Looks like SMTP issue, check your machines port status, if anti virus is blocking the port, etc.,Also check windows logs to get more information on why it is not working.