Configuring Dynamic Send Ports for Office 365 Outlook
Published Aug 31 2020 03:03 PM 5,290 Views

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 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):

 

<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 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).

 

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.

 

12 Comments
Copper Contributor

Thanks for the detailed steps. Successfully emails are sent from Application. 

After sending the mail, SendPort is suspended with below error message. 

 

An unexpected failure occurred when processing a message. The text associated with the exception is "Object reference not set to an instance of an object.
".

 

Please help, if I have missed any configuration.

 

Thanks,

Poornima

 

 

Hi Poornima,

 

More details are needed to better diagnose the issue. One way to start is by opening a support request at 

https://support.serviceshub.microsoft.com/supportforbusiness.

(Servers -> BizTalk Server).

 

Thanks,

 

Emmanuel

Copper Contributor

Hi Poornima,

have you been able to solve the issue yet? I have the same issue.

Also I found that BTS2020 CU2 claims support for WINSCP 5.17.8 or above but it is hard wired to WinSCP 5.17.6! For cyber security reasons an upgrade to 5.17.10 minimum would be very desirable, as some major CVEs have been fixed in 5.17.10.

However I recommend the developers mark the reference to winscp , newtonsoft etc dlls. as Requires Specific Version = False before compiling .... and then just document what version was tested working so upgrades to newer versions can be applied and tested by customers such as us.

 

Also BTS2016R2 CU8 adds the new O365 Adapter but the 2016 R2 version of that adapter is not HTML email capable, whilst the 2020 CU2 version does send HTML emails (followed by  Object reference not set to an instance of an object. as resumable in the Messagebox...but it did send the email )

 

I logged two tickets before and never got a reply... So is it worthwhile logging tickets or better shaming on forums to be publicly exposed to receive some attention?

Copper Contributor

Hi Poornima,

wondering if you are using a custom pipeline for the O365 Mail adapter outbound? If you are using a native Biztalk default pipeline, which one is that . that you are using?

Copper Contributor

Looks like the SMTP adapter that is as per documentation deprectated still works, only no longer works with HTML emails but TEXT emails only? And HTML Emails end up becoming an attachment in themselves at least in my outlook client they do, weirdish.

Copper Contributor

Looks like the html issue in BTS 2020 is due to different flags used for content type for smtp and o365 adapter.

so BTS2016 R2 CU8 no html emails with O365...but with BTS2020 smtp and O365 both can do HTML emails! ;)

only gotta figure out the object reference error now.

 

Also interesting is that in BTS2016 O365 seems to not like sending out more than a handful emails, but in BTS2020 no problem bombarding O365 with emails and no threshhold error message...

Copper Contributor

PS: I don't get "Object reference not set to an instance of an object."  in BTS2016 R2 CU8 but I DO get this in BTS2020 CU2 with the exact same bindings!

 

Copper Contributor


I'm getting the same error on BTS2020CU2 as @Phill35 - Biztalk sends the request to graph api, and it looks it finishes without problems, but after that throws the exception

about "Object reference not set to an instance of an object." in Microsoft.BizTalk.Adapter.Office365.Helper.HttpHelper.SendAsync(System.Net.Http.HttpMethod, string, string, string).

Rolling back to the CU1 does not solve the problem. As a temporary workaround I enabled routing for failed messages on the E-mail dynamic port, and just reroute "failed" messages to a folder for review.

Copper Contributor

MS Support has recognized the issue and provides a fix upon request or otherwise in a future CU.

Copper Contributor

I was just doing a small POC on dynamic send port using Office365 Outlook Email and I got the exact same issue:

 

A message sent to adapter "Office365 Outlook Email" on send port "POC.BizTalk.SendFancyEmail_1.0.0.0_POC.BizTalk.SendFancyEmail.SendHTMLEmail_SendOutlookPort_b89d2574cb2578fd" with URI "O365Mail://myemail" is suspended.
Error details: An unexpected failure occurred when processing a message. The text associated with the exception is "Object reference not set to an instance of an object.

 

any way to get my hand on that fix?

 

regards,

Sandro

Copper Contributor

Log a support ticket with microsoft.

They will give you the fix.

However the next issue is that O365 as threshold limits on 30 emails per minute and so many per hour , per day etc.

So if you sending 100 emails in a go it will bomb out. There isn't any pretty solution to overcome that yet. Been playing with a throttling pipeline but that causes biztalk to slow down and run out of threats. Another idea is to write email jobs to a table and then fetch them from there with polling and the fetching bit of code to obey Office 365's threshold limits...  etc... 

I haven't solve it yet for me, and we regularily sent more then 30 emails per minute...

 

Microsoft

@Phili35 I would recommend to test using a dedicated host for this send with settings to throttle all the time, but not the full 300 seconds (default). You can e g change throttling time from 300 seconds down to 15 seconds to be able to get a good flow still and then throttle on e g 5 threads and DB size some lower limit (e g 50-200) to limit this. In my testing I did see there is a bit of buffer where messages are put in Outbox so you may be able to put more than 30 at once, but if you go well beyond you may end up with all threads stuck waiting. Thus my recommendation to also put throttling on threads. To not run out of CLR max worker threads as this can cause some other issue, I would recommend to have enough CLR max worker threads configured for this still. 

Version history
Last update:
‎Jun 23 2023 08:26 AM
Updated by: