Messages sent from a dynamic send port with transport type set to one of the Office 365 Outlook adapters need to provide the UserTokenIdentifier context property. This identifier is created when the user signs in to Office 365, which is done when creating a static send port, 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):
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.
The demo scenario is based on a simple orchestration:
Received messages follow the schema:
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.
Name of the adapter transport type:
Office365 Outlook Email
Office365 Outlook Calendar
Office365 Outlook Contact
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).
(only for O365 Email) Email address to send mails to, if the transport type is Office 365 Outlook Email.
(only for O365 Email) Email subject .
(only for O365 Calendar) Calendar where the calendar items are created, when using Office 365 Outlook Calendar transport type.
<![CDATA[content]] where content can be either:
Calendar item in XML according to the Office365OutlookCalendarSend.xsd provided in the BizTalk installation folder under SDK\Schemas.
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 Server\SDK\Schemas (more info in Office 365 Outlook Adapters in Action).
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
// 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;
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.
BizTalk code is attached to this post for reference.