SOLVED

How to have app send message to channel without configuring connector

Copper Contributor

I know it is possible as Monday.com and Smartsheet integrations both do this. You can configure the app by allowing `adminconsent` and then selecting (on the web-service not in teams) which team & channel to have the service post to. Then the web application is able to make posts into that channel without the user configuring a connector/webhook.  In addition when I look into the channel that was mapped, there is no connector configured.

These apps have the exact functionality I'm looking for, and so far the only way to do this that I know of is to use the /messages graph api found here or to configure a connector.

The /messages api cannot be used by the application as far as I can tell. Though Monday.com appears to have a disclaimer that they are utilizing the beta features of the graph api.

So how can I have my Teams app send a message to a specific channel within an organization without having to have the user configure a connector?

Screen Shot 2020-03-19 at 12.06.25 PM.png

5 Replies
best response confirmed by adamhouck (Copper Contributor)
Solution

@adamhouck,

 

You could send message in a team from your app by doing a POST API call to below endpoint.

{serviceURL}/v3/conversations/{conversationId}/activities/{activityId} 

 

When bot is added into a group/team ConversationUpdate event is called in bot framework. You can cache the user details and serviceURL. And you can use these detail to post a message in teams or group.

@subhasish-MSFT  thank you, this is exactly what I was looking for. At first I dismissed this approach because I didn't realize a ConversationUpdate event was fired when the app was installed, I thought it needed direct user input.

 

That being said if I save the Conversation Reference from the initial app installation, can I use that indefinitely to post in other channels of the Team, or will it expire at some point like an Oauth Token?

@adamhouck , You have to store the team Id, tenant Id, conversation Id(in case of personal scope). These are unique Ids and can be stored indefinite time.  

@subhasish-MSFT Thank you, I successfully implemented this based off the Microsoft example here https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs/16.proactive-m... 

But I can't seem to authenticate correctly after restarting my server when using a saved conversation reference.  I did put in a call to `MicrosoftAppCredentials.trustServiceURL()` as the example shows.  Is there something else I am missing to authenticate after re-instantiating the `BotFrameworkAdapter` on server restart with a saved conversation reference?

{ Error: Authorization has been denied for this request.
at new RestError (...../node_modules/@azure/ms-rest-js/lib/restError.ts:18:5)
at ..../node_modules/@azure/ms-rest-js/lib/policies/deserializationPolicy.ts:117:27
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
code: undefined,
statusCode: 401,
request:
WebResource {
streamResponseBody: false,
url: 'https://smba.trafficmanager.net/amer/v3/conversations/{convo ID}%40thread.skype/activities/{activiyID}',
method: 'POST',
headers: HttpHeaders { _headersMap: [Object] },
body: '{"type":"message","serviceUrl":"https://smba.trafficmanager.net/amer/","channelId":"msteams","from":{"id":"{ID}","name":"CrossLead Dev Local"},"conversation":{"isGroup":true,"conversationType":"channel","id":"{ID}","tenantId":"{ID}"},"recipient":{"id":"{ID}","aadObjectId":"{ID}"},"text":"The bot encountered an error or bug.","inputHint":"acceptingInput","replyToId":"{ID}"}',
query: undefined,
formData: undefined,
withCredentials: false,
abortSignal: undefined,
timeout: 0,
onUploadProgress: undefined,
onDownloadProgress: undefined,
operationSpec:
{ httpMethod: 'POST',
path: 'v3/conversations/{conversationId}/activities/{activityId}',
urlParameters: [Array],
requestBody: [Object],
responses: [Object],
serializer: [Object] } },
response:
{ body: '{"message":"Authorization has been denied for this request."}',
headers: HttpHeaders { _headersMap: [Object] },
status: 401 },
body: { message: 'Authorization has been denied for this request.' } }


const msBotAdapter = new BotFrameworkAdapter({
appId: {ID as string}
appPassword: {ID as string},
});

//Some people also said to do this, but never used it anywhere. It doesn't seem to help
const msCreditials = new MicrosoftAppCredentials(
{ID as string},
{ID as string}
);

//Save Conversation Reference from when the app was installed into teams
const conversationReference: {
[key: string]: Partial<ConversationReference>;
} = {
activityId: '{activity ID}',
//@ts-ignore
user: {
id:
'{ID}',
aadObjectId: '{ID}',
},
bot: {
id: '{Bot Id}',
name: '{Bot Name}',
},
//@ts-ignore
conversation: {
isGroup: true,
conversationType: 'channel',
tenantId: '{tenant ID}',
id: '19:{ID}@thread.skype',
},
channelId: 'msteams',
serviceUrl: 'https://smba.trafficmanager.net/amer/',
};


const postMessage = async () => {
MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl);
await msBotAdapter.continueConversation(
conversationReference as any,
async turnContext => {
// If you encounter permission-related errors when sending this message, see
// https://aka.ms/BotTrustServiceUrl
await turnContext.sendActivity('test message);
}
);
}




Turns out it was due to using an outdated dependency, `botbuilder` https://github.com/microsoft/botframework-sdk#readme though I was only on 4.7.2 and the latest was 4.8.0.

We will probably forgo these dependencies in favor of working with the REST API's directly like Stackoverflow. https://stackoverflow.blog/2019/11/04/a-technical-deep-dive-into-our-ms-teams-integration/

 

Having our teams integration totally fail due to a slightly newer version of the botframework package coming out is not a longterm option.

1 best response

Accepted Solutions
best response confirmed by adamhouck (Copper Contributor)
Solution

@adamhouck,

 

You could send message in a team from your app by doing a POST API call to below endpoint.

{serviceURL}/v3/conversations/{conversationId}/activities/{activityId} 

 

When bot is added into a group/team ConversationUpdate event is called in bot framework. You can cache the user details and serviceURL. And you can use these detail to post a message in teams or group.

View solution in original post