The web is full of desperate pleas for help by prematurely bald developers who have discovered the fatal flaw in the shiny new ASP.NET 2.0
System.Net.Mail.SmtpClient class. This is touted as overcoming all the problems of the old variant, that could not even be configured for credentials without resorting to some heavy-duty tricks.
As has been discovered by countless people, while the new
SmtpClient() class in ASP.NET 2.0 is neat, easy to use, and configurable via Web.Config, they forgot one thing to make it configurable. The
EnableSsl property is not settable via Web.Config. So, big deal you say - just write a line of code and set it manually... Problem is, you do not write the code that instantiates the
SmtpClient. The most well known problem is with the suite of new login controls, which have the capability of sending mail in some circumstances. Works fine - unless you need to enable SSL for the SMTP connection. Fortunately, there's a well-known workaround since these controls expose an event called
SendingMail, where you can do magic things including affecting how the mail is sent - most simply by taking over responsibility of sending it.
I hit the wall, really hard, trying to use the
System.Web.Management.TemplatedMailWebEventProvider class for the development of my Online Password Manager, Xecrets. This is a provider that can subscribe to health monitoring events, and send them via e-mail. Using
SmtpClient() of course, with the instantiation hidden deep in its innards of sealed and internal classes in System.Web.dll. No events to the rescue this time either.
After hours of fruitless searching, I finally come to the conclusion that I needed a work-around, ugly as it may be. So, here's where the Decorator pattern meets Reflection. Sigh. It ain't pretty, but it does work, and I do get to use the otherwise rather nice and advanced
TemplatedMailWebEventProvider (the same technique can be used for the
SimpleMailWebEventProvider, or any provider derived from
In the end, it's just a few lines of code (comments removed for brevity):
public class TemplatedMailWithSslWebEventProvider : WebEventProvider
private TemplatedMailWebEventProvider _templatedProvider;
ConstructorInfo constructor = typeof(TemplatedMailWebEventProvider)
.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,
null, new Type, null);
_templatedProvider = (TemplatedMailWebEventProvider)constructor
public override void Initialize(string name, NameValueCollection config)
if (config == null)
throw new ArgumentNullException("config");
FieldInfo field = typeof(MailWebEventProvider)
BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(_templatedProvider, new SmtpClientWithSsl());
public static MailEventNotificationInfo CurrentNotification
public override void Flush()
public override void ProcessEvent(WebBaseEvent raisedEvent)
public override void Shutdown()
What's left to do?
All that's left for you to do is to define the
SmtpClientWithSsl() class, deriving from
System.Net.Mail.SmtpClient() whose developer, probably by the same oversight that forgot about SSL, also forgot to make it sealed. Fortunately. Here, two wrong almost makes one right!
You must also register your provider in Web.Config, of course.
The morale of the story
One of the morals of this story is to really think about the use of sealed and internal. My first try was to implement a custom templated e-mail provider, but it turns out that was quite a job, and I could not override or use anything from System.Web.dll because it was all sealed and used lots of internal helpers. If you really need to hide the implementation that bad, it might be better to introduce a public base class, where the essential interfaces are exposed as protected methods and properties. When you limit a class to sealed, and it depends on lots of additional logic, do consider making that logic available at least to alternative implementations and give it a base to inherit from.
This is the first version.