Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to create an SMTP Trace Listener

0.00/5 (No votes)
28 Jan 2003 1  
This article describes how to create an SMTP Trace Listener for use with .NET diagnostics

Introduction

This article describes how you can extend .NET's native TraceListener capabilities to provide your application with the ability to send SMTP mail messages.  This article assumes you are familiar with .NET Trace capabilities (part of System.Diagnostics).  The article also assumes that you know what a TraceListener is.  If you do not know, read the article - Writing custom .NET trace listeners By Vagif Abilov Vagif explains fairly well what TraceListeners are and how to use them.

Background

How many times have you developed an application that needed to send an e-mail notifying you or a support group that some error, or other special condition has occurred? In most cases this application must also log the same or similar information to either a database or to some type of flat file for later use. I recently found an article on TheCodeProject.com - Writing custom .NET trace listeners By Vagif Abilov. This was a good article that described ways to build your own trace listeners.  I decided to put this article to practical use and implement something that people might be able to use in thier apps.

Why would you need an SMTP Trace Listener?

In building my applications there was a need to send some of the same tracing information to e-mail recipients in certain situations - i.e. exception thrown, user account locked out, etc. This can be especially handy when developing web applications that are hosted remotely. If you don't know what is going on with your web app and a support call comes in you could be in a bad situation. This code could (and should) be extended to include support for attaching files (but I didn't because I don't need it yet). This way you could send a log file, or other diagnostic information along with the error message within an e-mail so you don't have to log into the remote server to get it.

Using the code

SMTPTraceListener

The SMTPTraceListener class is derived from the TraceListener class found in the System.Diagnostics library. The methods you MUST override are:

  • public override void Write(string Message)
  • public override void WriteLine(string Message)

You can also override the following methods (this implementation does not - as it is not required for basic functionality):

  • public virtual void Fail(string);
  • public virtual void Fail(string, string);
  • public virtual void Close();
  • public virtual void Flush();

In order to get this class to work in your applications, you must create a reference to the System.Web.dll in your project references.   The code for the SMTPTraceListener.cs is listed below:

using System;
using System.Diagnostics;
using System.Web.Mail;



namespace RK.TraceListeners
{
    /// <summary>

    /// Summary description for SMTPTraceListener.

    /// </summary>

    public class SMTPTraceListener : TraceListener
    {
        string m_sSMTPServer;
        string m_sFrom;
        string m_sTo;
        string m_sMessage;
        string m_sSubject;
        //Normal mail priority by default

        MailPriority m_oPriority = MailPriority.Normal;

        public MailPriority Priority
        {
            get{return m_oPriority;}
            set{m_oPriority = value;}
        }

        public string Server
        {
            get{return m_sSMTPServer;}
            set{m_sSMTPServer = value;}
        }

        public string From
        {
            get{return m_sFrom;}
            set{m_sFrom = value;}
        }

        public string To
        {
            get{return m_sTo;}
            set{m_sTo = value;}
        }

        public string Message
        {
            get{return m_sMessage;}
            set{m_sMessage = value;}
        }

        public string Subject
        {
            get{return m_sSubject;}
            set{m_sSubject = value;}
        }

        public SMTPTraceListener() 
        {
            
        }

        public SMTPTraceListener(string ListenerName) 
            //: base(ListenerName)

        {
            
        }

        public SMTPTraceListener(string ListenerName, 
                string Server, string From) 
            //: base(ListenerName)

        {
            m_sSMTPServer = Server;
            m_sFrom = From;            
        }

        public SMTPTraceListener(string Server, string From) 
            : this("SMTPTraceListener", Server, From)
        {
            
        }

        public override void Write(string Message)
        {
            try
            {
                SmtpMail.SmtpServer  = m_sSMTPServer;
                System.Web.Mail.MailMessage oMessage = new MailMessage();
                Message.Priority = m_oPriority;
                Message.From = m_sFrom;
                Message.To = m_sTo;
                Message.Body = Message;
                Message.Subject = m_sSubject;
                SmtpMail.Send(oMessage);
                this.Flush();
            }
            catch(Exception ex)
            {    
                throw ex;
            }
        }

        public void Write(string Server, string From, 
           string To, string Subject, string Message)
        {
            this.m_sSMTPServer = Server;
            this.m_sFrom = From;
            this.m_sTo = To;
            this.m_sSubject = Subject;
            this.m_sMessage = Message;
            try
            {
                this.Write(Message);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }

        public override void WriteLine(string Message)
        {
            try
            {
                this.Write(Message);
            }
            catch(Exception ex)
            {
                throw ex;
            }
        }
    }//SMTPTraceListener

}//namespace

Using SMTPTraceListener in your code

Along with including reference to System.Web.Dll, you must include these using directives

using System;
using System.Web.Mail;
using System.Diagnostics;            
With that you should be able to include the following anywhere in your code:
RK.TraceListeners.SMTPTraceListener oTrace = new 
RK.TraceListeners.SMTPTraceListener("YourServer.YourDomain.com", "mike");

Trace.To = "Someone@Yourdomain.com";
Trace.Subject = "SMTP Trace Listener Test - Do not reply";                        
            
string obj1 = "Someone,  The SMTP Trace Listener is now working!";            
            
Trace.Listeners.Add(oTrace);
Trace.Write("Message from Trace.Write(message)") ;
Trace.Write(obj1) ;        
Notice in the above code the use of the System.Diagnostics Trace component without declaration. This is because every .NET application natively has a Trace object ready and available for use.

Points of Interest

A few things that were somewhat interesting when developing this component:

  • I did not call the base class constructors (which you will notice are commented out in the SMTPTraceListener).  For some strange reason, sometimes when you call the base constructor and then try to use the class you get the following exception:
    System.Exception: Cannot create CDO.Message object 
  • I found out that the System.Web.Mail is simply a wrapper around the Collaborative Data Objects (CDOSys.dll) which ships with Outlook 98 or better.  This CDOSys.dll is a COM dll and therefore makes the SMTPMail component very SLOW.  Probably because of all the Interop it has to do.
  • Because of the performance issues associated with interop, you should use the write method sparingly, as it may slow down your app.  An alternative is to implement a Write method with no parameters.  Then within your application code, set properties of the listener, then spawn a thread passing the write method.  This is a way to work around the performance problem.
  • In the SMTPTraceListener Write method - I call the Flush method.  This forces the e-mail output to happen right then, and makes the component more stable.  With the Flush taken out of the Write method, I was experiencing some inconsistent behavior - i.e. exceptions thrown sometimes but not always... goofy problem perhaps someone knows why?
  • The FROM attribute in the message object should be set to either a vaild return address, or one that doesn't include any special characters.  (Thanks to Guy Swartwout and Michael Witczak for figuring that out).  In my personal opinion the SMTPMail.Send method should return a more useful exception than Cannot create CDO.Message object for everything.

History

  • 1/24/2003 - Article created

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here