Botbuilder-js: Can't send proactive messages to a channel until there's been some activity on this channel (from any user)

Created on 8 Jan 2019  路  10Comments  路  Source: microsoft/botbuilder-js

I am unable to send proactive messages to a channel that I have not yet communicated with _(during this run)_.

REPRO:

  1. start my bot written in C# or JS (JS for this example) - V4, latest release
  2. try to send a new message to a Skype user for which I've already saved the reference activity information via createRefferenceActivity()
  3. example code:
    const reference = JSON.parse('{"activityId":"1546604462703","user":{"id":"29:1.... await this._adapter.continueConversation(reference, async (proactiveTurnContext) => { await proactiveTurnContext.sendActivity(Testing proactive message); });

EXPECTED: to see the message in the Skype

ACTUAL: Exception

[onTurnError]: Error: Authorization has been denied for this request.
(node:20616) UnhandledPromiseRejectionWarning: Error: Authorization has been denied for this request.
warning.js:18
at new RestError (c:_Test\Test\TestWeb\Test2JSnode_modules\ms-rest-js\eslib\restError.js:7:28)
at c:_Test\Test\TestWeb\Test2JSnode_modules\ms-rest-js\eslibpolicies\deserializationPolicy.js:92:37
at
at process._tickDomainCallback (internal/process/next_tick.js:228:7)
(node:20616) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 5)
warning.js:18
(node:20616) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

### NOW THE INTERESTING PART...

REPRO:

  1. Go to any Skype user who's connected with the bot
  2. Send a message
    Now my proactive message (above) works.

[bug]

Most helpful comment

FIXED!

Thanks so much for your help. After getting onto the correct path it seems that LOTS of people were or are having the same problem -- might want to add this tip to the proactive sample.

Call this before starting and everything is good to go.

BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://smba.trafficmanager.net/apis/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://facebook.botframework.com/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://telegram.botframework.com/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://kik.botframework.com/', new Date(8640000000000000));

All 10 comments

I think I understand your problem. If so....

This is because the bot doesn't know that a user has joined the conversation until the user first sends a message. The bot sends ConversationUpdate when the conversation is created, but the user's ConversationUpdate isn't sent until they send a message.

This is by design to prevent spam. The only channel where proactive messages work without the user sending the message first is Email (and the Emulator).

You can, instead, try using contactRelationUpdate, but be aware that this is only sent when a user adds or removes the bot as a contact. It would look something like:

// Sample for Skype: in ContactRelationUpdate event
    else if (activity.Type == ActivityTypes.ContactRelationUpdate && activity.ChannelId == "skype")
{
    // Greeting
}

If you think your problem is different, can you provide:

  • More detailed steps for each user
  • Sample code where you think the problem might lie, possibly in your state accessors

Yes, this is a different problem.

After restarting, I can't send a proactive message to users that I've previously communicated with _(until there has been some activity on the channel)_.

REPRO:

  1. Bot is restarted
  2. Bill chats with my bot in Skype [Everything is happy - reference saved via createRefferenceActivity()]
  3. Sally chats with my bot in Skype [Everything is happy - reference saved]
  4. Bot is restarted
  5. Try to send a proactive message to Bill -- ERROR
  6. Try to send a proactive message to Sally -- ERROR
  7. Bill (or any user, even someone not Bill or Sally) sends a message to my Bot [this will work]
  8. Try to send a proactive message to Bill -- NOW WORKS
  9. Try to send a proactive message to Sally -- NOW WORKS

More info -- it feels like something is happening or not happening with the bot framework connector magic which I haven't seen the source code to. It feels like this service never gets hooked up or started until some message comes from Skype, Facebook, Telegram, Kik, etc.

Maybe there's something that I need to do at start-up to say that I'm alive?

I'm still leaning towards it being a conversationUpdate issue, but if not, it's likely something state-related.

Can you share the following code snippets:

  • Code related to memory/storage in index.ts
  • Any code using state accessors in the rest of your bot
  • Your createRefference() code

And for clarification, is this bot deployed or are you testing locally?

_Bot is in production and has been running for a year on 4 platforms -- ported recently to JS from C#._

index.js -- nothing special here that I can see

// Listen for incoming requests.
server.post('/api/messages', (req, res) => {
    adapter.processActivity(req, res, async (context) => {
        console.log(context.activity.type);

REPRO#3 - even with emulator

  1. start JS bot
  2. load Bot Framework Emulator
  3. Click Restart Conversation button in Emulator
    -----> debug log shows "conversationUpdate" << context.activity.type
  4. stop JS bot
  5. restart JS bot
  6. type "hello" in Bot Framework Emulator which is still connected
    -----> debug log shows "message" << context.activity.type

NOTE that there is no "conversationUpdate" until any new user interacts with the channel but our proactive messages are allowed *AFTER any message is received from the channel. *

Code related to memory/storage in index.ts
Any code using state accessors in the rest of your bot
Your createRefference() code

We do have our own storage which writes to SQL server and our own conversation state which uses this storage...
class MyConversationState extends BotState {
...but this doesn't seem to be involved in the flow.

Creating the reference could be but it's the same thing we get back from the botframework call...

Here is that code.

        const reference = {
            activityId: `${new Date().getTime()}`,
            user: { id: data.RecipientCode, name: data.RecipientName },
            bot: { id: data.ChannelCode, name: data.ChannelUsername },
            conversation: { id: data.ConversationCode },
            channelId: data.ChannelName,
            serviceUrl: data.ChannelServiceUrl
        };

    await adapter.continueConversation(reference, async (proactiveTurnContext) => {
        await proactiveTurnContext.sendActivity(`Testing proactive message`);
    });

_I posted here because I believed that this is a bug in the backend but am open to all possibilities._

What about this article?

From https://stackoverflow.com/questions/43551841/botframework-proactive-unauthorizedaccessexception-on-cold-call/43554192

I have encountered this error before. Essentially, the channel that the message is coming from is "trusted". The workaround is to trust that channel access.

Try this (first parameter should be the service url):

MicrosoftAppCredentials.TrustServiceUrl(@"https://skype.botframework.com", DateTime.MaxValue);

Maybe it is a trust thing?

https://github.com/Microsoft/BotBuilder/issues/3329

How do you use this in JS?

https://github.com/Microsoft/botbuilder-dotnet/blob/e176ce91d5611bce57132248af55049003d9dc00/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs

I'll be working on your issue throughout the day. In the meantime, to answer your last question, the equivalent repo/library can be found here:

microsoftAppCredentials.ts

FIXED!

Thanks so much for your help. After getting onto the correct path it seems that LOTS of people were or are having the same problem -- might want to add this tip to the proactive sample.

Call this before starting and everything is good to go.

BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://smba.trafficmanager.net/apis/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://facebook.botframework.com/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://telegram.botframework.com/', new Date(8640000000000000));
BotConnector.MicrosoftAppCredentials.trustServiceUrl('https://kik.botframework.com/', new Date(8640000000000000));

Glad you got it working! I'll work on getting it added to samples and documentation.

@qpongo I am having this issue now as well. What is the BotConnector variable that you're referring to in your fix?

I am using the BotFrameworkAdaptor and I notice that it is using MicrosoftAppCredentials but I can't directly interact with that class. Would you mind posting a more complete code sample?

@mdrichardson did you get a chance to add this to the samples and documentation? Can you link here if so? Thank you!

@alexbielen Nothing in the samples, but the docs have a section for it, now.

You should be able to use MicrosoftAppCredentials from the botframework-connector package.

Was this page helpful?
0 / 5 - 0 ratings