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://eggheadcafe.com/FileUpload/1397230300_ConfiguredSMTP.UtilsProject.jpg
Add to the project references so that they are as the following screenshot
http://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.com/FileUpload/1397230300_RcvPortProps.jpg
Add send port
Next we add the Send shape and configure it as follows.
http://eggheadcafe.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://eggheadcafe.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://eggheadcafe.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://eggheadcafe.com/FileUpload/1397230300_SndShapeProps.jpg
All that remains is to add a Strong Name Key and save
http://eggheadcafe.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://eggheadcafe.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://eggheadcafe.com/FileUpload/1397230300_sender1email.jpg
http://eggheadcafe.com/FileUpload/1397230300_sender2email.jpg
http://eggheadcafe.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.