Sending an HTML-Formatted E-Mail Message from BizTalk Server

Text emails from BizTalk are really simple to send; you can easily configure the SMTP adapter in BizTalk and send text emails. You can also use the XSLT Transform Pipeline component (BizTalk Server Example) which is a Microsoft Sample Pipeline component that converts your XML that contains data into HTML. You can use the similar solution by changing the XSL template and extract relevant data from your XML. Make sure about the path of your XSL file in the component. For practice use the same solution until you get your desired HTML output and you are ready to use it in your BizTalk Solution.

Well for rapid development and BizTalk guys who aren't very good with XSL just like me would get in a lot of troubles. But depends on the scenario of course seeing your problem you can better decide for which solution you want to go. You can explore the above solution on MSDN.

Days back I wanted to email an error report to my business staff about the TCP messages that were failed in a batch. The batch contained about 16000 records and an estimate of 500-1000 records fail in the batch. I wanted to use the solution above but making an XML in my component (yes I was sending message to TCP through my .NET component because using the TCP adapter from codeplex opens and closes the connection each time and the Tuxedo guy receiving the messages doesn't likes that). Well in the response I can catch the status and build the error message fields. While each error message has four fields about the customer record I decided to make a mail template and store it in a string. Then I built the whole mail message at runtime which had the mail message body with error records and stats information then I had to mail it through the BizTalk SMTP adapter.

I just return the HTML body in a string from my .NET component to BizTalk Orchestration in which I am building the email message and giving it to the SMTP adapter. In BizTalk as we know a message can be made of multi message parts and each message part can have its context. And a whole message which is made up of these parts has its own message context. An email message can have a text/html body with attachments. So BizTalk translates the Email Message body as one message part and each attachment as different body parts. Concluding that an email message in BizTalk is a multi-part message. So lets make a Multi-Part message in BizTalk for email.

multi-part-messages

multi-part-messages
After creating the multi-part message you have to configure its type. I made a string which contains the HTML body but don't configure the Message Type as string because as you know sending the String type would convert the message into XML when passing through the pipeline. The message type should be of RawString. The RawString Type is not in the SDK. You have to built it yourself compile the class as a separate assembly GAC it and add its reference to your project. Then you can configure the message type as RawString Type. To built the type below is the code. You can find this code on MSDN.

using System;
using System.IO;

using System.Text;
using System.Xml.Serialization;

using System.Runtime.Serialization;

using Microsoft.XLANGs.BaseTypes;

 

namespace Microsoft.Samples.BizTalk.XlangCustomFormatters

{

    public abstract class BaseFormatter : IFormatter

    {

        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;

        }

    }

}


After creating the message type you have to construct the email message. In the message assignment shape use the following code to construct the message.

EmailMessage.EmailMessageBody = new Microsoft.Samples.BizTalk.XlangCustomFormatters.RawString(EmailStr);

            SMTPUtils.Part.SetContentType(EmailMessage.EmailMessageBody, "text/html");

            Port_Email(Microsoft.XLANGs.BaseTypes.Address) = "mailto:address@ myenterprisedomain.com ";

            EmailMessage(SMTP.Subject) = "IPO Refund process completed";

            EmailMessage(SMTP.CC) = "[email protected]";

            EmailMessage(SMTP.From) = "fromadd@ myenterprisedomain.com ";

            EmailMessage(SMTP.SMTPHost) = "hostname";
Where Port_Email is the send port set to dynamic binding and uses the custom pipeline in which we use the MIME/SMIME Encoder pipeline component. You can drag and drop the MIME/SMIME Pipeline component on your custom sendpipeline file in the encode stage as shown below.
send_pipeline
You don't have to configure the properties of the component. When configuring the send port set its binding to dynamic and select the custom send pipeline which you built as below.


Coniguring Dynamic Send Port


After Setting up the send port the SMTPUtils class is also a custom code that has to be compiled as a separate assembly, GAC'd and you have to add a reference to the assembly in your project. You can find the code to the SMTPUtils class on
MSDN.

using System;

using Microsoft.XLANGs;

//comes from Microsoft.XLANGs.BaseTypes.dll using MIME;

//comes from Microsoft.Biztalk.GlobalPropertySchemas.dll

namespace SMTPUtils

{

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;

    }

}

}
You can make a separate project for SMTPUtils and RawString Class and put it in the GAC. In this way you can successfully send HTML formatted Email messages through your orchestration. As you are using dynamic binding you have to do all the configurations in your orchestration and not from your administration console. Try pulling out the email addresses and other things if they tend to change in the future from SSO or from a database at runtime if you can.


Similar Articles