BizTalk Configure and Send SMTP Mail Based on Message Within an Orchestration

This article explains how to build a BizTalk application that will allow run time configuration and sending of SMTP email from within an orchestration via a dynamic send port. The contents of a simple incoming xml message are interrogated and used to dynamically dertermine the From, To, Subject and Body text of a SMTP message before sending it. By building upon the techniques shown in this article developers will be able to create dynamic SMTP enabled BizTalk applications.

This article shows how to configure SMTP mail at run time from within a BizTalk orchestration using the inbuilt SMTP adapter via a dynamic send port. The contents of the incoming message will be used to configure the From, To, subject and Body of the SMTP mail, allowing for a very fluid and dynamic method of configuring SMTP mail.

By building and deploying this example BizTalk application you will be able to configure and send email messages simply by dropping a XML file into a directory.

This article assumes that you have a working knowledge of BizTalk Server 2006 r2 and that you have access to a system where you have privileges to create, deploy and configure BizTalk applications.

The BizTalk artefacts you will build are as follows:

• A new BizTalk solution
• A message schema
• An Orchestration
• A Receive Port
• A Send Port
• A Send Pipeline
• 2 .Net classes supporting the configuration of the SMTP mail

Pre-requisites

A SMTP send adapter with host instances needs to be created. To do this, please see my post on sending simple SMTP mail from an orchestration here:

http://www.eggheadcafe.com/tutorials/aspnet/9dd0f346-baf9-4674-a50f-1716445b26bc/sending-smtp-email-from-w.aspx

Create the Solution.

First we start off by creating the two supporting C# projects.

1. ConfiguredSMTP.Utils Project

Open Visual Studio and create a new C# Class Library project and call it Configured.Utils.cs

http://nullskull.com/FileUpload/1397230300_ConfiguredSMTP.UtilsProject.jpg

Add to the project references so that they are as the following screenshot

http://nullskull.com/FileUpload/1397230300_ConfiguredSMTP.UtilsRefs.jpg

Rename the Class1.cs file to utils.cs and paste the following code into the blank class

using System;
using Microsoft.XLANGs.BaseTypes;
using MIME;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using System.Runtime.Serialization;


namespace ConfiguredSMTP.Utils
{

    
/// <summary>
    
///
    
/// </summary>
    
public abstract class BaseFormatter : IFormatter
    {
         
private String test = string.Empty;

        
public virtual SerializationBinder Binder
        {
            get {
throw new NotSupportedException(); }
            set {
throw new NotSupportedException(); }
        }

         
public virtual StreamingContext Context
        {
            get {
throw new NotSupportedException(); }
            set {
throw new NotSupportedException(); }
        }

         
public virtual ISurrogateSelector SurrogateSelector
        {
            get {
throw new NotSupportedException(); }
            set {
throw new NotSupportedException(); }
        }

         
public abstract void Serialize(Stream stm, object obj);
        
public abstract object Deserialize(Stream stm);
    }

    
public class RawStringFormatter : BaseFormatter
    {
         
public override void Serialize(Stream s, object o)
        {
            RawString rs = (RawString)o;
             
byte[] ba = rs.ToByteArray();
            s.
Write(ba, 0, ba.Length);
        }

         
public override object Deserialize(Stream stm)
        {
             
StreamReader sr = new StreamReader(stm, true);
            
string s = sr.ReadToEnd();
            
return new RawString(s);
        }
     }

    [CustomFormatter(
typeof(RawStringFormatter))]
    [Serializable]
     
public class RawString
    {
         [
XmlIgnore]
        
string _val;

        
public RawString(string s)
        {
             
if (null == s)
                 
throw new ArgumentNullException();
            _val = s;
        }

         
public RawString()
        {
         }

         
public byte[] ToByteArray()
        {
             
return Encoding.UTF8.GetBytes(_val);
        }

         
public override string ToString()
        {
             
return _val;
        }
     }

    
/// <summary>
    
/// Summary description for Class1.
    
/// </summary>
    
///
    [Serializable()]
    
public class Utils
    {
         
public class Part
        {
             
public Part()
            {
            }
            
public static void SetContentType(Microsoft.XLANGs.BaseTypes.XLANGPart part, string contentTypeValue)
             {
                 
part.SetPartProperty(typeof(Microsoft.XLANGs.BaseTypes.ContentType), contentTypeValue);
             }
             
public static void SetFileName(Microsoft.XLANGs.BaseTypes.XLANGPart part, string fileName)
            {
                 
part.SetPartProperty(typeof(MIME.FileName), fileName);
            }
            
public static System.Xml.XmlDocument SetInfopathForm(System.Xml.XmlDocument part, string InfopathFormUrl)
             {
                 
// Delete existing processing instructions.
                 
foreach (System.Xml.XmlNode pi in part.SelectNodes("processing-instruction()"))
                 {
                     
pi.ParentNode.RemoveChild(pi);
                 }
                 
// Add an xml declaration
                 
System.Xml.XmlDeclaration decl = part.CreateXmlDeclaration("1.0", null, null);
                 
part.InsertBefore(decl, part.DocumentElement);
                 
// Create the mso-application procesing instruction.
                 
System.Xml.XmlProcessingInstruction progid = part.CreateProcessingInstruction("mso-application", "progid='InfoPath.Document'");
                 
part.InsertBefore(progid, part.DocumentElement);
                 
// Create the mso-infoPathSolution processing instruction
                 
System.Xml.XmlProcessingInstruction form = part.CreateProcessingInstruction("mso-infoPathSolution", "PIVersion='1.0.0.0' href='" + InfopathFormUrl + "'");
                 
part.InsertBefore(form, part.DocumentElement);

                 
return part;
            }
        }
    }
}


This is the code for the entire utils.cs class so simply copy it over the existing (empty) class code.

I got the above code from http://msdn.microsoft.com/en-us/library/ee253435%28BTS.10%29.aspx and it is necessary to use it so that the body of the email is sent as a string. If you tried to send the body as a System.String it will get formatted as xml, which isn’t what we want here, and will probably end up as an attachment. Using this code enables us to send the body of the SMTP mail as text.

Add a strong name key to the project and you’re done.

2. Add the Process project to the Solution

This project contains the class that will hold the methods that we call from the orchestration to configure the SMTP attributes

Add to the project references so that they are as the following screenshot

http://nullskull.com/FileUpload/1397230300_ProcessProps.jpg

Note how we reference the newly created Configured.SMTP.Utils project

Rename Class1.cs to ProcessMail.cs and paste the following code into it.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace Process
{
    [Serializable()]
     
public class ProcessMail
    {
         
public string GetRecipientFromMessage(InMsgRoot msg)
        {
             
switch (msg.Value1)
             {
                 
case "1":
                     
return  "my.email@smtpprovider.co.uk";
                 
case "2":
                     
return  "my.email@smtpprovider.co.uk";
                 
case "3":
                     
return  "my.email@smtpprovider.co.uk";
                 
default:
                     
return  "my.email@smtpprovider.co.uk";
            }
        }

         
public string GetSubjectFromMessage(InMsgRoot msg)
        {
             
switch (msg.Value1)
             {
                 
case "1":
                     
return "Subject 1";
                 
case "2":
                     
return "Subject 2";
                 
case "3":
                     
return "Subject 3";
                 
default:
                     
return "A default subject";
            }
            
        }

         
public string GetSenderFromMessage(InMsgRoot msg)
        {
             
switch (msg.Value1)
             {
                 
case "1":
                     
return "Sender1@BizTalksamples.com";
                 
case "2":
                     
return "Sender2@BizTalksamples.com";
                 
case "3":
                     
return "Sender3@BizTalksamples.com";
                 
default:
                     
return "DefaultSender@BizTalksamples.com";
            }
        }

         
public ConfiguredSMTP.Utils.RawString GetBodyFromMessage(InMsgRoot msg)
        {
             
string body = "";
            
switch (msg.Value1)
             {
                 
case "1":
                     
body = "This is body text 1.";
                     
break;
                 
case "2":
                     
body = "This is body text 2.";
                     
break;
                 
case "3":
                     
body = "This is body text 3.";
                     
break;
                 
default:
                     
body = "This is the default body text.";
                     
break;
            }

            
return new ConfiguredSMTP.Utils.RawString(body);
        }
     }
}


Note: The email addresses in the GetRecipientFromMessage method (above) need to resolve to valid email addresses via SMTP server.

The above code contains the methods that we call from the orchestration. Notice how the only parameter for each method is of type InMsgRoot. This is the input message type in the biztalk project we will be creating next.

Add a strong name key and we’ve now finished the 2 .Net supporting projects.

Build the BizTalk project.

Add an empty BizTalk project to the solution and call it ConfiguredSMTP.

I prefer to group similar artefacts together in separate folders so I add three new folders to the project. One called Orchestrations, one called Pipelines and one called Schemas. This is simply the way I like to work but if you don’t, it will not affect the solution.

Add the references that are shown in the following screenshot.

http://nullskull.com/FileUpload/1397230300_BizTalkProjProps.JPG

Note: Some of these are added when you create the solution.

Create the input message schema

Add a schema to the project and call it inMsgSchema.xsd. Its structure should be as shown in the screenshot below

http://nullskull.com/FileUpload/1397230300_InMsgSchema.JPG

Create the Send Pipeline

Right click the Pipelines folder (or the Project if you didn’t create it) and select Add->New item. In the dialog box select Pipeline files in the left pane and Send Pipeline in the right pane. A blank pipeline should appear in Visual studio. From the BizTalk toolbox pane click and drag the MIME\SMIME encoder onto the pipeline and drop it under the Encode section.

http://nullskull.com/FileUpload/1397230300_pipeline.jpg

Right click your newly dropped MIME\SMIME encoder and select Properties. Configure the values to be as they are in the following screenshot

http://nullskull.com/FileUpload/1397230300_MimePipeProps.jpg

The greyed out values are auto generated so ignore those. That’s all that you have to do for the pipeline so save the file as SendSmtpPipeline.btp and close it.

Create the Orchestration

Next we add an orchestration containing the following artefacts: One send and one receive port, a Receive shape a Construct message shape containing a Message assignment shape, an expression shape and a send shape. We will also create two message types. One for the input message and one for the multipart output message.

By following these steps you should end up with an orchestration looking something like this.

http://nullskull.com/FileUpload/1397230300_Orchestration.JPG

Create the message types


You need two message types. One for the incoming message and one for the outgoing message.

Incoming message

In the Orchestration View window, right click on the Messages folder and select the New Message option. Adjust the new message properties until they are as in the screenshot below.

http://nullskull.com/FileUpload/1397230300_InMsgProps.JPG

Outgoing message

This needs to be a Multi-part message type so in the Orchestration view window right click the Multi-part Message Types folder and select New Multi-part Message Type. A new Multi-part message will be created with the default name of MultipartType_1. Expand this to reveal the MessagePart_1 element. Right click the MessagePart_1 element and select Properties. Change the properties so they are as the following screenshot

http://nullskull.com/FileUpload/1397230300_MultipartMsgBodyProps.JPG

Add Process reference type.

To access the methods in the Process.cs classs we need to add  a variable of type Process.ProcessMail. This is one of our refenced assemblies. Add this by right clicking on the variables folder in the orchestration view window and adding a new variable. Configure the variable properties as the following screenshot shows.

http://nullskull.com/FileUpload/1397230300_ProcessVarProps.jpg

In the Type dropdown browse the referenced assemblies to find Process.ProcessEmail

Add receive port

Next we add the Receive shape and configure it as follows.

http://nullskull.com/FileUpload/1397230300_RcvPortProps.jpg

Add send port

Next we add the Send shape and configure it as follows.

http://nullskull.com/FileUpload/1397230300_SndPortProps.jpg

Note how we set the Send Pipeline to the one we created earlier.

Add the Receive shape

Drag a Receive shapre from the toolbar onto the orchestration and configure its properties as follows.

http://nullskull.com/FileUpload/1397230300_RcvShapeProps.jpg

Add the Construct Message and Message Assignment Shapes

Drag a ConstructMessage shape to the orchestration and drop it under the Receive shape. Set the constructed message property to be of type MultiPartMessage (you created this earlier)

Next drop a MessageAssignment shape into the MessgaeConstruction shape. Double click it to open expression editor. Paste the following code into the expression editor and click OK to save and close.

MultiPartMsg.Body = process.GetBodyFromMessage(InMsg);
MultiPartMsg(SMTP.Subject) = process.GetSubjectFromMessage(InMsg);
MultiPartMsg(SMTP.From) = process.GetSenderFromMessage(InMsg);
MultiPartMsg(SMTP.SMTPHost) = "smtp.tiscali.co.uk";
MultiPartMsg(SMTP.SMTPAuthenticate) = 0;


These are the method calls we created in the Process.cs class.

Add rcpt variable

This is simply a System.String variable that is used to hold the recipient address. Add a new variable and configure it as follows.

http://nullskull.com/FileUpload/1397230300_RcptVarProps.jpg

Add the Expression Shape

This shape configures the email recipient based on a value in the incoming message.

Drag an Expression shape onto the orchestration and drop it below the MessageConstruction shape. Double click it to open the expression editor and paste the following code into it.

rcpt = process.GetRecipientFromMessage(InMsg);
Snd_Smtp_Port_1(Microsoft.XLANGs.BaseTypes.Address)="mailto:" + rcpt;

Click OK to save and close.

Add send shape

Next we add the send shape that will be sending our configured email.

Drag and drop a Send shape below the Expression shape. Configure it so as it contains the following properties.

http://nullskull.com/FileUpload/1397230300_SndShapeProps.jpg

All that remains is to add a Strong Name Key and save

http://nullskull.com/FileUpload/1397230300_BizTalkProjSNK.jpg

And we’re done with the BizTalk project.


Add the Schema Class project

Right click the solution and add a new C# Class library project and call it BusinessServices.SchemaClasses.

From the inMsgSchema.xsd schema created earlier, we need to create a class file from it and add it to the solution. The class file is created using xsd.exe. Open a cmd window, navigate to the folder where the inMsgSchema.xsd is and execute the following command

xsd.exe inMsgSchema.xsd –c –l:C (or l:VB for VB.Net)

The schema class file inMsgSchema.cs should be created in the same directory. Now cut and pate ths schema class file into the root directory the new BusinessServices.SchemaClasses project. You will have to include it in the project. Do this by highlighting the BusinessServices.SchemaClasses project and then clicking the Show All Files button located at the top of the Solution Explorer window. Right click the Schema class file and select ‘Include in Project’. You can delete the automatically created Class1.cs file from the project.

Build and Deploy

Before you build and deploy make sure that in addition to a strong name key that you set an application name in the BizTalk project properties dialog box. Otherwise your application will be deployed to BizTalkApplication1.

Ok, now build and deploy your solution. All that remains to do before creating and dropping in a test inMsgSchema file is to configure the application in BizTalk Admin Console. The Orchestration should be using the SMTP host you created, the receive location should be configured as follows:

http://nullskull.com/FileUpload/1397230300_RcvLocProps.jpg

Obviously the receive URI should be somewhere on your local machine.

The send pipeline of the send port should be referencing the SendSmtpPipeline.btp pipeline we created near the beginning of this article.

Now right click the app and start it. Your configurable SMTP app is noe ready to receive messages and send emails.

All that remains is to construct some sample input messages.

Construct input messages

Using a text editor of your choice create three files as below and save them as InMsg1.xml, InMsg2.xml and InMsg3.xml.

Message 1
<ns0:InMsgRoot Value1="1" Value2="1" Value3="1" xmlns:ns0="http://ConfiguredSMTP.Schemas.inMsgSchema"/>

Message  2
<ns0:InMsgRoot Value1="2" Value2="2" Value3="2" xmlns:ns0="http://ConfiguredSMTP.Schemas.inMsgSchema"/>

Message 3
<ns0:InMsgRoot Value1="3" Value2="3" Value3="3" xmlns:ns0="http://ConfiguredSMTP.Schemas.inMsgSchema"/>

Save these somewhere on your hard drive and drop them one by one into the directory your receive location is monitoring. After a few seconds they should be consumed and shortly after a new mail message like the ones below should appear in your inbox.

http://nullskull.com/FileUpload/1397230300_sender1email.jpg

http://nullskull.com/FileUpload/1397230300_sender2email.jpg

http://nullskull.com/FileUpload/1397230300_sender3email.jpg

Conclusion

This article explains how to build a BizTalk application that will allow run time configuration and sending of SMTP email from within an orchestration via a dynamic send port. The contents of a simple incoming xml message are interrogated and used to dynamically dertermine the From, To, Subject and Body text of a SMTP message before sending it. By building upon the techniques shown in this article developers will be able to create dynamic SMTP enabled BizTalk applications.

By BiZTech Know   Popularity  (9380 Views)