Sending an HTML Email without an Orchestration
There is plenty of information on the Net relating to being able to send an HTML email from BizTalk using a dynamic SMTP port and an orchestration (see here and here). At a client I needed to achieve the same objective, but without the use of an orchestration and with a static SMTP port.
The basic requirement was that the customer was looking to develop a solution that would make use of the standard send port filters, outbound map resolution, and BizTalk's management console to provide a flexible solution for sending HTML email to one or more standard email addresses. They specifically did not want to use an orchestration and a dynamic send port, as they wanted to use the send port filters as the "rule base" to determine which messages should be routed to which static email addresses, and they wanted to use the BizTalk administration console to maintain the email addresses and the filter rules (which are mainly BTS.MessageType filters).
This set of requirements presented the following challenges:
- How do you architect the solution so that you can setup and manage a specific send port once (e.g. a send port for billing@joesrouting.com) and route different messages to this send port. Yet, each message needs to be transformed in accordance with the message's unique type before the message is sent to the specified email address?
- Once you understand how you are going to manage the routing and selective transformation requirements, how do you ensure that the selected transformation produces the HTML formatted email content specific to the message type you are sending?
- The last challenge, although far easier to state, was somewhat more complex to resolve: How do you send an HTML email via a static send port?
Routing and Transforming Messages
For those who have worked with BizTalk for a while, this problem will not present too much of a challenge, as this functionality is native to BizTalk. The send port in BizTalk follows the following process (simplified for the purposes of this post):
- Receive the outbound message, in accordance with the send port's subscription.
- Find any maps configured for the current send port, where the source schema in the map matches the current message's BTS.MessageType context property.
- Execute the map, if a match is found. If no match is found the message is passed on to step 4.
- Call the configured pipeline, passing in the output of the map.
- Execute the pipeline.
- Pass the output of the pipeline to the configured adapter.
- The adapter then performs its logic on the finalised message.
Through this process the send port is able to receive any message type, and for each message type that is received a different map may be executed before the message is processed further. This process therefore fulfills the first "challenge" in this scenario, as we will.
Producing HTML Output
Using this approach to route and transform messages, the next challenge is how to produce HTML from a map. Once again, BizTalk provides a simple solution to achieve this: a BizTalk map can be configured to use an XSLT file, by choosing the XSLT file from the "Custom XSL Path" property in the map's properties. The XSLT that you use can then produce HTML and it can use content from the source schema to produce an HTML formatted output containing data from the input message. An example of such an XSLT file is shown below:
<xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" method="xml" standalone="yes" version="1.0" encoding="UTF-8" />
<xsl:template match="/">
<html>
<head>
<title>Billing Enquiry: Corporate</title>
</head>
<body>
<p>
The details below relate to a billing enquiry receive at <xsl:value-of select="//Header/QueryTime" /> on <xsl:value-of select="//Header/QueryDate" />.
</p>
<table style="border:none;padding: 0px;width:100%;">
<tr>
<td>Contact Person:</td>
<td>
<xsl:value-of select="//Query/ContactName" />
</td>
</tr>
<tr>
<td>Contact Number:</td>
<td>
<xsl:value-of select="//Query/ContactNo" />
</td>
</tr>
<tr>
<td>Account Number:</td>
<td>
<xsl:value-of select="//Query/AccNo" />
</td>
</tr>
<tr>
<td>Query:</td>
<td>
<xsl:value-of select="//Query/Description" />
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
A particular snag that caught me during the implementation of this XSLT within the map is that BizTalk Mapper kept adding a META tag into the produced HTML, and it would change the nature of some of the tags, e.g. if we had a tag that was "<br/>" in the XSLT file, it would come out as "<br>" once the map had been executed. It was only after I realised that I had forgotten the output control declaration that I realised why this was happening. The point is: make sure that you include the following line in your XSLT file to ensure the correct processing takes place:
<xsl:output omit-xml-declaration="yes" method="xml" standalone="yes" version="1.0" encoding="UTF-8" />
Sending HTML via a Static Send Port
With the routing sorted, and the maps producing HTML, the next challenge was to get the static send port to send the HTML in the body of the send port. The challenge here is that the SMTP adapter does not natively take the content of the message and put it into the body of the email being sent via the send port. Even if you select the "BizTalk message body part" option in the "Compose" tab of the SMTP adapter properties, the content of the message is not used as the body of the email. Instead, the message is sent as an attachment to a blank email. There are examples of how to ensure that a specific set of text is used as the body of the email, via a dynamic port, but there are no examples of how to do this for a static port.
After trying many different options the result was to use a pipeline component and pipeline to set the "ContentType" property of the message being sent to "text/html". Once this was done, the SMTP adapter was more than happy to take the content of the BizTalk message and place it within the body of the email it sent, and the email was received as an HTML-formatted email. The code used to set this is shown in the single line below:
inmsg.BodyPart.ContentType = "text/html";
In Summary
With the challenges solved, the final result was a flexible solution that did not use an orchestration, and which used a map per message type, and a send port per email address (with each send port configured with the appropriate maps and with the pipeline that set the content type).
Comments
Anonymous
September 11, 2008
There is plenty of information on the Net relating to being able to send an HTML email from BizTalk usingAnonymous
October 22, 2008
The comment has been removedAnonymous
October 24, 2008
The comment has been removedAnonymous
December 07, 2008
can you pls post the same biztalk project. rgds, NikAnonymous
December 10, 2008
Hi Nik, Unfortuantely I don't have the BizTalk project anymore. The detail above should be sufficent to get you going, however. If you need more help then let me know and perhaps I can help with the specific project you are dealing with.Anonymous
March 10, 2009
The comment has been removedAnonymous
April 19, 2010
The comment has been removedAnonymous
September 12, 2012
dont forget to add following: pInMsg.BodyPart.ContentType = "text/html"; pInMsg.BodyPart.Charset = "UTF-8";Anonymous
January 05, 2015
What do you use as the schema for the outbound document? My send port keeps failing with an map error saying "Finding the document specification by message type "html" failed".