Hello fellow coders. Here is part 3 of the how to develop a MPS Provider article.
Today I am going to focus on writing a provider which actually does something relatively useful.

The SMTPMailProvider (as I will call it from now on) will enable a MPS Named Procedure to send e-mail to a specified user.

The Project will consist of 3 parts.

  1. The Provider
  2. The Provider Namespace
  3. A Namespace which will create a user, mailbox enable that user and then send e-mail to the user. (this will require some sort of Mail system. For our purposes I will use the POP3 Mail service shipping in Windows Server 2003)

OK here we go

Setting up the environment

You will need to use add/remove Windows Component Wizard on one of the servers in your development environment and add the "E-mail Services" Component.

Part1: Writing the SMTPMailProvider

The SMTPMailProvider will use the System.Web.Mail Namespace to create and submit the Mail message it will have one public method called SendMail, the Method will take a couple of mandatory and a few optional parameters.

Mandatory Properties

  • sendTo
  • mailFrom
  • subject

Optional Properties

  • messageText
  • attachementPath
  • smtpServerName
  • messageFormat

How do we implement it:

Open Visual Studio 2003 and Create a new MPF Provider Project and Name it SMTPMailProvider

Add the System.Web.Mail Namespace to the references and insert

using System.Web.Mail;

Create the public sendMail Method by adding the Provider Method Atributes

[ProviderMethodAttribute("sendMail",
ProviderHandlerType.process,
Description="Sends an Email to one or more recipients",
AccessType=ProviderAccessType.publicAccess)]

 

Now create the method

public void sendMail(IXMLDOMNode node)
{
}

Now it is time to grab the mandatory properties from the incoming XML Request

// get the executeData node from the incoming XML request
IXMLDOMNode executeDataNode = node.selectSingleNode("/executeXml/executeData");

/// <remarks>
/// get the required elements from the incoming XML request
/// </remarks>
/// <param name="sendTo"> is required, delimit multiple receipients with semicolons(we are not checking for email address syntax</param>
/// <param name="mailFrom"> is the required (must be a valid email address the smtp server can relay)</param>
/// <param name="subject"> is required and gets inserted into the message subject</param>
string sendTo = this.GetRequiredElementValue(executeDataNode, "sendTo");
string mailFrom = this.GetRequiredElementValue(executeDataNode, "mailFrom");
string subject = this.GetRequiredElementValue(executeDataNode, "subject");

Now look if we have any optional parameters in the request

///<remarks>
///get the optional elements from the incoming XML request
///</remarks>
///<param name="messageText">string or HTML Blob that forms the message body</param>
///<param name="attachmentPath">the physical path to a fileattachment to be added to the message
/// there can only be one attachment in this implementation
/// if the path is invalid or not accessible the procedure will fail</param>
///<param name="smtpServerName">the NetBios, IP address or FQDN for the SMTP server
/// which will send the message, not supplying this paramater will default
/// to localhost</param>
///<param name="messageFormat">the format for the messagebody can be text or html</param>
string messageText = this.GetOptionalElementValue(executeDataNode, "messageText");
string attachmentPath = this.GetOptionalElementValue(executeDataNode, "attachmentPath");
string smtpServerName = this.GetOptionalElementValue(executeDataNode, "smtpServerName");
string messageFormat = this.GetOptionalElementValue(executeDataNode, "messageFormat").ToLower();

Ok that we relatively easy, we use th XML Handling methods which come with the provider Wizard template to retrieve the madatory and/or optional parameters.

For a relatively simple provider with only one method which does not require rollbach you can add the "action" code right here. For more complicated provider or providers with multiple methods and rollback requirements it is better to encapsulate each method into a seperate private class and then call it from here. For this sample I will add the action code right here

Let's new up a message object

//Create an empty Mail Message
MailMessage newMessage = new MailMessage();

Add the recipient, sender and subject to the message

newMessage.From = mailFrom;
newMessage.To = sendTo;
newMessage.Subject = subject;

Lets see if we have a message bod text, if you want to send an HTML Message then you will have to encode the HTML into the XML request, we will look into this a little later

if(messageText.Length != 0)
   {
      newMessage.Body = messageText;
   }
   

Now set the message format if the format string does not specify html or text then lets default to text and rather not fail.

if(messageFormat.Length != 0)
 {
         
switch(messageFormat)
         {
         // set the message format
         case "html":
            newMessage.BodyFormat=MailFormat.Html;
            break;
         case "text":
            newMessage.BodyFormat=MailFormat.Text;
            break;
         default:
            // we are not going to fail the send if an invalid 
            // messageFormat comes in just send as Text and we should be fine
            newMessage.BodyFormat=MailFormat.Text;
            break;
            }
}

Check if we have an attachment path and see if we can find it and attach it to the message

if(attachmentPath.Length != 0)
   // we got an attachmentpath lets try to attach the file
   // if this fails we will fail the request
   {
      try
         {
               MailAttachment newAttachment =
new MailAttachment(attachmentPath);
               newMessage.Attachments.Add(newAttachment);
         }
      catch(Exception e)
         {
               // Attachment adding failed
               
return ;
          }
      }

Here we will fail the request before sending the mail if we have encountered an error during attaching the file specified.

If we did not fail to add the attachment let's go and set the remainder of the optional paramters or the defaults.

// set the SMTP Server if any
if
(smtpServerName.Length != 0)
      {
            SmtpMail.SmtpServer =smtpServerName;
      }
            else
//default to localhost 
      {
            SmtpMail.SmtpServer ="localhost";
      }

In the code above we use the System.Web.Mail.SmtpMail Class to configure the mailserver we want to use to send the mail, this will default to localhost if none is specified.

Now lets send the message we have created above on its way

// now send the message
try
   {
      SmtpMail.Send(newMessage);
   }
      catch
(Exception e)
   {
      // sendig the message failed
      return
;
   }
}

Now that we are done with this lets create the Provider Namespace XML File, to do this edit the ProviderNS.XML from the solution explorer to look like this.

<namespace name="SMTPMailProvider" description="" readOnly="0" providerSource="SMTPMailProvider.Provider">

 <procedure name="sendMail" description="Sends an email using SMTP" access="public" type="write" perfEnabled="0" saveDataForRollback="0" auditEnabled="0"/>

</namespace>

Now we should be done with the base provider and the namespace so we can go ahead and build the solution hit CTRL-Shift-B, if all is well the build succeeded and we are good to go and register the DLL and go ahead and try the provider out.

Open a command prompt and CD to the Solution Folder in my case this is

C:\MPFSDK\Providers\SMTPMailProvider

Type the following commandline (without the line breaks of course)

\WINDOWS\Microsoft.NET\Framework\v1.1.4322\RegAsm.exe /codebase .\bin\Debug\SMTPMailProvider.dll

Ignore the warning for now. We are going to deal with the signing later on. Now we will go into the Provisioning Manager and register the provider Namespace. From the same commandline type

      provnamespace \MPFSDK\Providers\SMTPMailProvider\ProviderNS.xml

You should get a response like this

   The namespace(s) have successfully been added or updated.

The next step is going to be to create the ManagedMail Namespace which will allow us to send email and also setup a mail enabled user.

This will require some sort of mailenabled user we can send the mail to. I'll assume for now you have a mail system somewhere you can send mail to and also that there exists a SMTP Server we can use to send the mail from.