Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Step by Step Guide on Building Your First Email Application with the File System Watcher

4.00/5 (4 votes)
22 Sep 2012CPOL4 min read 27.8K  
Step by step guide on building your first email application with the file system watcher

Introduction

“Necessity is the mother of invention”… so the true…idea of this application comes to my mind in the class for “application development foundation” while studying the file system watcher. We had a problem with the college online blackboard and one of my friends was not able to access the online blackboard and hence he was not able to download the lectures and presentations from there. So we always had to email the presentation to him in every lecture, so this idea of an automated mailing system came to my mind.

Creating the Watcher

So, the first step is to create a file system watcher. We are going to use FileSystemWatcher class for this and this listens to the file system change notifications and raises events when a directory, or file in a directory changes. A word of caution: By default, the buffer is set to a size of 4 KB. A 4 KB buffer can track changes on approximately 80 files in a directory. Each event takes up 16 bytes in the buffer, plus enough bytes to store the name of the file, in Unicode (2 bytes per character), that the event occurred on.
The main properties that we are going to use here are IncludeSubdirectories, NotifyFilter and the event Created. You can use different events depending on the requirement. Here is the list of all the events from the FileSystemWatcher class.

  • Changed: Occurs when a file or directory in the specified Path is changed.
  • Created: Occurs when a file or directory in the specified Path is created.
  • Deleted: Occurs when a file or directory in the specified Path is deleted.
  • Disposed: Occurs when the component is disposed by a call to the Dispose method.
  • Error: Occurs when the internal buffer overflows.
  • Renamed: Occurs when a file or directory in the specified Path is renamed.
C#
FileSystemWatcher fsw = new FileSystemWatcher(@"Directory Path");
fsw.IncludeSubdirectories = true;
fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
fsw.Created += new FileSystemEventHandler(fsw_Changed);

The Windows operating system notifies your component of file changes in a buffer created by the FileSystemWatcher. If there are many changes in a short time, the buffer can overflow. This causes the component to lose track of changes in the directory, and it will only provide blanket notification. Increasing the size of the buffer with the Internal Buffer Size property is expensive; as it comes from non-paged memory that cannot be swapped out to disk, so keep the buffer as small yet large enough to not miss any file change events. To avoid a buffer overflow, use the NotifyFilter and IncludeSubdirectories properties so you can filter out unwanted change notifications.

You have to set the EnableRaisingEvents to true to start monitoring the events.

C#
fsw.EnableRaisingEvents = true;
Console.WriteLine("Press a key to end the program.");
Console.ReadKey();

Sending the Email

For email, you have to use the System.Net.Mail namespace. The System.Net.Mail namespace contains classes used to send electronic mail to a Simple Mail Transfer Protocol (SMTP) server for delivery.
The MailMessage class represents the content of a mail message. The SmtpClient class transmits email to the SMTP host that you designate for mail delivery. You can create mail attachments using the Attachment class.

Creating the SMTP client….

The SmtpClient class is used to send e-mails to an SMTP server for delivery. Port 587 is for users to send out emails on. Here is how to create the smtpclient object.

C#
var fromAddress = new MailAddress("email address", "Name of the Sender");
var toAddress = new MailAddress("email address", "Receiver Name");
const string fromPassword = "password";
const string subject = "subject";
const string body = "body of the email";
var smtp = new SmtpClient
{ Host = "smtp.gmail.com", Port = 587, EnableSsl = true,DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false, Credentials = new NetworkCredential(fromAddress.Address, fromPassword)};

Creating the Attachment

I have just created a filestream and have provided this to the constructor of attachment. Attachment content can be a String, Stream, or filename.

C#
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
 
Attachment data = new Attachment(fileStream,"Name");

Creating the Mail Message

Finally, we come to creating the email message. The sender, recipient, subject, and body of an e-mail message may be specified as parameters when a MailMessage is used to initialize a MailMessage object. These parameters may also be set or accessed using properties on the MailMessage object.

After assembling your e-mail message, you can send it by using the end method.

C#
using (var message = new MailMessage(fromAddress, toAddress) 
{ Subject = subject, Body = body })
{
message.Attachments.Add(data);
try
{
smtp.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Exception caught in CreateMessageWithAttachment(): {0}", ex.ToString());
}
}

Now We Have a Problem

While running this application, I came across the problem with larger attachments. In slower networks, it may take a long time to attach the files so I tried to use asynchronous programming here. I tried to start the second thread in the event of the filesystemwatcher class like this:

C#
private static void fsw_Changed(object source, FileSystemEventArgs e)
        {  
            Program p = new Program();
 
            DoWorkDelegate del = new DoWorkDelegate(p.DoWork);
 
            IAsyncResult ar = del.BeginInvoke(e.FullPath,new AsyncCallback(p.DoWorkCallback), del);  
        }

You can put all the code that is time consuming in the dowork method.

And you can use AsyncCallback to give a confirmation of the attachment attached or mail sent.

C#
public void DoWorkCallback(IAsyncResult res)
        {
            Console.WriteLine("Message sent");
 
            DoWorkDelegate del = res.AsyncState as DoWorkDelegate;
 
            del.EndInvoke(res);
        }

Further Development and References

  • MSDN classes

You can play around with the filesystemwatcher and use it to create a lot of cool applications. You can use it to log the application installation details and to monitor the changes in a particular directory.

Thanks.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)