This article is contributed. See the original author and article here.

BizTalk 2020 CU1 introduced support for dynamic send ports in the Office 365 Outlook adapters. In this post, we go over this improvement into more details.

 

Pre-requisites

 

Messages sent from a dynamic send port with transport type set to one of the Office 365 Outlook adapters require the UserTokenIdentifier context property. This identifier is created when the user signs in to Office 365, which is done in the transport properties of the Office 365 Outlook adapters as documented in Office 365 Outlook adapters in BizTalk.

 

Once a user is signed-in, the UserTokenIdentifier is retrieved from the bindings, as shown below, in the case of an exported Mail send port (placeholder nnnnnnnn-nnnn-nnnn-nnnnnnnnnnnn):

 

 

<SendPort Name="MailSendPort2" IsStatic="true" IsTwoWay="false" BindingOption="0" AnalyticsEnabled="false">
      <Description xsi:nil="true" />
      <TransmitPipeline 
           Name="Microsoft.BizTalk.DefaultPipelines.PassThruTransmit" 
           FullyQualifiedName="Microsoft.BizTalk.DefaultPipelines.PassThruTransmit, Microsoft.BizTalk.DefaultPipelines, Version=3.0.1.0, Culture=neutral,                     
               PublicKeyToken=31bf3856ad364e35" Type="2" TrackingOption="None" Description="" />
      <PrimaryTransport>
        <Address>O365Mail://BizTalkTestAccount1@outlook.com</Address>
        <TransportType Name="Office365 Outlook Email" Capabilities="11" ConfigurationClsid="48b96e09-bd96-4f46-95ef-57accc55f23d" />
        <TransportTypeData>&lt;CustomProps&gt;&lt;DefaultCC vt="8" /&gt;&lt;UserTokenIdentifier vt="8"&gt;nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn&lt;/UserTokenIdentifier&gt;&lt;FileAttachments vt="8" /&gt;&lt;DefaultTo vt="8"&gt;BizTalkTestAccount2@outlook.com&lt;/DefaultTo&gt;&lt;EmailAddress vt="8"&gt;BizTalkTestAccount1@outlook.com&lt;/EmailAddress&gt;&lt;AttachBizTalkMessageParts vt="11"&gt;0&lt;/AttachBizTalkMessageParts&gt;&lt;DefaultSubject vt="8"&gt;Hi from BizTalkTestAccount1&lt;/DefaultSubject&gt;&lt;DefaultImportance vt="8"&gt;Normal&lt;/DefaultImportance&gt;&lt;/CustomProps&gt;</TransportTypeData>

 

 

Note that the UserTokenIdentifier is tied to a signed-in account and a transport type.  A static send port needs to be created for each Office 365 transport type in order to get an identifier for each. For a given sign-in, the value of the UserTokenIdentifier may be the same for all Office 365 transport types, but static send ports need to be created for each transport type nonetheless.

 

Other important points to be aware of:

  • Static send ports can be deleted afterwards. They are not needed once the UserTokenIdentifiers are known.
  • UserTokenIdentifiers remain valid regardless of whether a dynamic or static send port exists or not, and after port deletions.
  • The same UserTokenIdentifier can be used by multiple ports.

 

Scenario

 

The demo scenario is based on a simple orchestration:

 

O365DynPortOrch.JPG

 

Received messages follow the schema:

 

O365DynPortInputSchema.JPG

 

Element

Description

UserTokenIdentifier

Value of the UserTokenIdenfier acquired ahead of time by exporting the static ports.

The UserTokenIdentifier is provided by received messages. In the general case, the UserTokenIdentifier can come from any source. For instance one could keep a mapping of email addresses to UserTokenIdentifiers and make this mapping available for lookup at runtime.

PortType

Name of the adapter transport type:

  • Office365 Outlook Email
  • Office365 Outlook Calendar
  • Office365 Outlook Contact

PortAddress

Any unique identifier for the dynamic send port. Typically it is a user-friendly string. Since we’re using an Office 365 account, we used an email address (e.g., BizTalkAccount1@outlook.com).

To

(only for O365 Email) Email address to send mails to, if the transport type is Office 365 Outlook Email.

Subject

(only for O365 Email) Email subject .

Calendar

(only for O365 Calendar) Calendar where the calendar items are created, when using Office 365 Outlook Calendar transport type.

Payload

<![CDATA[content]] where content can be either:

  • Email body
  • Calendar item in XML according to the Office365OutlookCalendarSend.xsd provided in the BizTalk installation folder under SDKSchemas.
  • Contact item in XML following the Office365OutlookContactSend.xsd in the same location.

CDATA is used to make the XML payloads (calendar and contact) opaque to XML parsers on the receive side. The payloads are used on the send side.

 

In the case of calendar and contact items, the payloads are based on the schemas provided in the BizTalk installation folder under C:Program Files (x86)Microsoft BizTalk ServerSDKSchemas (more info in Office 365 Outlook Adapters in Action).

 

Examples

 

Email

<ns0:Root xmlns:ns0="http://DynamicO365SendPort.ReceiveSchema">
    <UserTokenIdentifier>nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn</UserTokenIdentifier>
    <PortType>Office365 Outlook Email</PortType>
    <PortAddress>BizTalkAccount1@outlook.com</PortAddress>
    <To>BizTalkAccount2@outlook.com</To>
    <Subject>Hello</Subject>
    <Payload><![CDATA[<?xml version="1.0" encoding="utf-8"?><EmailBody>body</EmailBody>]]></Payload>
</ns0:Root>

 

Calendar

<ns0:Root xmlns:ns0="http://DynamicO365SendPort.ReceiveSchema">
    <UserTokenIdentifier>nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn</UserTokenIdentifier>
    <PortType>Office365 Outlook Calendar</PortType>
    <PortAddress>BizTalkAccount1@outlook.com</PortAddress>
    <To>BizTalkAccount2@outlook.com</To>
    <Subject>Hello</Subject>
    <Calendar>Calendar</Calendar>
    <Payload>
        <![CDATA[
            <ns0:Event xmlns:ns0="http://schemas.microsoft.com/BizTalk/Office365OutlookCalendar/Send">
                <subject>Let's meet</subject>
                <body><content>Info for the upcoming meeting</content></body>
                <start><dateTime>2020-06-25</dateTime><timeZone>Pacific Standard Time</timeZone></start>
                <end><dateTime>2020-06-25</dateTime><timeZone>Pacific Standard Time</timeZone></end>
                <attendees>
                    <emailAddress><address>BizTalkAccount2@outlook.com</address><name>BizTalkAccount2</name></emailAddress>
                </attendees>
           </ns0:Event>
        ]]>
    </Payload>
</ns0:Root>

 

Contact

<ns0:Root xmlns:ns0="http://DynamicO365SendPort.ReceiveSchema">
    <UserTokenIdentifier>nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn</UserTokenIdentifier>
    <PortType>Office365 Outlook Contact</PortType>
    <PortAddress>BizTalkAccount1@outlook.com</PortAddress>
    <To>BizTalkAccount2@outlook.com</To>
    <Subject>Hello</Subject>
    <Payload>
        <![CDATA[
            <ns0:Contact xmlns:ns0="http://schemas.microsoft.com/BizTalk/Office365OutlookContacts/Send">
                <displayName>displayName_3</displayName>
                more contact fields
           </ns0:Contact>
        ]]>
    </Payload>
</ns0:Root>

 

 Dynamic Send Port Configuration

 

To keep things simple, an XML document is created on the fly and properties are added. The message creation expression is:

XMLMessage = new System.Xml.XmlDocument();

// Payload from the CDATA section of received messages
XMLMessage.LoadXml(ReceivedMessage.Payload);

// Token identifier (required)
XMLMessage(OfficeMail.UserTokenIdentifier) = ReceivedMessage.UserTokenIdentifier; 
XMLMessage(OfficeCalendar.UserTokenIdentifier) = ReceivedMessage.UserTokenIdentifier;
XMLMessage(OfficeContact.UserTokenIdentifier) = ReceivedMessage.UserTokenIdentifier;

// Transport type (required)
SendPort(Microsoft.XLANGs.BaseTypes.TransportType) = ReceivedMessage.PortType;

// Port address
SendPort(Microsoft.XLANGs.BaseTypes.Address) = PortAddress; // Generated in separate expression.

// Additional fields for Mail transport type
XMLMessage(OfficeMail.To) = ReceivedMessage.To;
XMLMessage(OfficeMail.Subject) = ReceivedMessage.Subject;

Note: Additional promoted are available for Mail transport type, such as CC, importance and attached files (see Office 365 Outlook Email Adapter).

 

The port address is generated from received messages by using the following expression:

if (ReceivedMessage.PortType == "Office365 Outlook Email")
{
    PortAddress = "O365Mail://" + ReceivedMessage.PortAddress;
}
else if (ReceivedMessage.PortType == "Office365 Outlook Calendar")
{
    PortAddress = "O365Calendar://" + ReceivedMessage.PortAddress + "/MyCalendars/" + ReceivedMessage.Calendar;
}
else if (ReceivedMessage.PortType == "Office365 Outlook Contact")
{
    PortAddress = "O365Contact://" + ReceivedMessage.PortAddress;
}

 

Putting it all together

 

The annotated view of the demo orchestration below illustrates the data flow. Received messages provide UserTokenIdentifiers and transport type to be used for the messages sent by the dynamic send port. 

 

O365DynamicSPOrch.jpg

 

BizTalk code is attached to this post for reference.

 

Brought to you by Dr. Ware, Microsoft Office 365 Silver Partner, Charleston SC.