2

I can't seem to figure out how to proactively message a MS teams channel using a Python Bot (botframework).

  1. An user installs my third-party MS teams bot, adding it to one of their Teams channels.
  2. My Bot needs to send ad-hoc messages as part of an event from an unrelated back-end system.

The botframework does not let you message channels at will, it needs a conversation reference. You can get a conversation reference in various ways, such as someone messaging the bot, or fetching the list of channels and constructing a conversationId from that.

Reading the documentation

The documentation will have you believe that it is in fact possible to send message at will, using the following steps:

  1. Get the user ID or team/channel ID (if needed).
  2. Create the conversation or conversation thread (if needed).
  3. Get the conversation ID.
  4. Send the message.

For step 1, how/when do I get the channel ID if there are no events that my Bot has been added to a channel?

For step 2, how do I create a conversation if I don't know what team channels there are?

Conclusion

Does someone know how to send a message to a MS Teams channel using a Python app/bot? It should not require user interaction. The app/bot gets added to a Teams channel, and it should immediately post a message inside this channel.

sf033
  • 107
  • 10

2 Answers2

1

I'm working on a sample for the pnp Teams samples repo on GitHub that I'm hoping to submit in the next few days. I haven't started on the documentation yet, but the code is fully functional, with both a C# and a Node.js version of the backend, which sends a -very- simple proactive message example (showing the most basic things you need) - hopefully it can be of use even though it's not in Python - see https://github.com/HiltonGiesenow/teams-dev-samples/tree/add-proactive-messaging-sample/samples/bot-proactive-messaging/src

Hilton Giesenow
  • 9,809
  • 2
  • 10
  • 24
  • Thank you for taking the time to write back. From looking at the NodeJS code, it is actually not sending proactive messages. They are based on an event, in this case a new member that gets added to the channel via `TeamsActivityHandler.onMembersAdded`. The `sendProactiveInfoAsync` function needs a `conversationReference`, so this implies some sort of previous event. My requirement is that a bot joins a Teams channel and is able to message the channel regardless of anyone joining the channel, or anyone messaging the bot previously. I am starting to think this is not possible. – sf033 Jan 14 '21 at 09:28
  • It sounds like maybe you're getting a bit confused between a Proactive Message and Welcome message...Have a look at https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-send-welcome-message?view=azure-bot-service-4.0&tabs=csharp and https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages?tabs=dotnet – Hilton Giesenow Jan 14 '21 at 09:45
  • `sendProactiveInfoAsync` is NOT sending a 'proactive' message, but you need certain fields later in order to do so. So it's sending a WELCOME message, but that message contains the fields NEEDED to send the proactive message later. That's why I named the function `sendProactive**Info**Async` – Hilton Giesenow Jan 14 '21 at 09:46
  • Hopefully that helps clarify? – Hilton Giesenow Jan 14 '21 at 09:47
  • I think I follow quite well? From the provided code, the welcome message activity is emitted when a (new) user joins a channel. From this event alone you may gather the necessary components to eventually send a proactive message. However, my requirement is that a **newly installed bot gets added to a Teams channel** - and we get no activity from this event. In the situation that no new members join the channel, `sendProactiveInfoAsync` never gets called, so you won't be able to send a proactive message. Please clarify this is the case :) – sf033 Jan 14 '21 at 10:21
  • ahh ok, now I understand, thanks for clarifying. I actually saw this morning that one of my bots did get the notification, but it was a side-loaded app, I haven't checked for store apps recently. There was another reported issue like this a few days ago that might be relevant - see https://stackoverflow.com/questions/65669683/teamsbot-how-do-i-get-the-team-id-from-a-conversationupdate-event in particular "We are checking internally with our team, will get back to you soon." from Microsoft – Hilton Giesenow Jan 14 '21 at 10:28
  • It -seems- like there might be a bug of some kind in Teams – Hilton Giesenow Jan 14 '21 at 10:29
  • That thread seems to do what I want (or partially, at least), indeed. Ill keep an eye out. Thanks. – sf033 Jan 14 '21 at 10:49
  • @sf033, Hilton has provided accurate solution for this question. – Mallipriya-MSFT Jan 15 '21 at 10:28
  • @Mallipriya-MSFT Did you read my question and requirements? To re-iterate; I have an app/bot, it gets added to a Teams channel. I get no event from this. Please tell me how I can detect if my app/bot is added to a Teams channel, and secondly how I can post a message to this channel without requiring any previous user interaction. – sf033 Jan 15 '21 at 12:56
  • Once the bot is added to a team, you can check the payload of ConversationUpdateEvent with membersAdded object to differentiate wheter bot was added or a user is added. Please go through this [document](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/bot-v3/bots-notifications#team-member-or-bot-addition). – Mallipriya-MSFT Jan 18 '21 at 00:42
  • You can even get user ID on the conversationupdate event and can build ConversationReference to proactively message the bot. Please have a look at this [sample of proactive messaging](https://github.com/microsoft/BotBuilder-Samples/blob/26e9964c21a166ff4c86f798e098e0ba3aef5e71/samples/python/16.proactive-messages/bots/proactive_bot.py#L14). – Mallipriya-MSFT Jan 18 '21 at 00:54
  • @Mallipriya-MSFT To re-iterate; **I get NO event when my bot is added to a Teams channel**. I know this because I'm doing a network capture `ngrep -dlo -qt -W byline port ...`. The only event I get is when an user adds the app/bot to his/her Teams, see also this paste: https://ghostbin.co/paste/mmzne/raw. The documentation says `Because this event is sent in both cases` - I only get ONE CASE, I get **no event when my bot/app is added inside a channel**. Inside the Teams application, the channel shows `"User X" has added "Bot" to the team - so it's definitely getting added. – sf033 Jan 18 '21 at 12:05
  • @JoaquínL.Robles Yes, the solution was simple. I was not deleting my app correctly. I had to uninstall it the correct way. I had some leftover debug apps that were "polluting" my endpoints and thus I was not receiving events for certain actions. – sf033 Aug 04 '21 at 16:22
1

Turns out the issue was that my on_teams_members_added() was not getting called because I kept deleting the app within Teams instead of uninstalling.

Make sure to:

  1. Click on the ... overflow menu next to the team name
  2. Pick Manage Team
  3. Select the "Apps" tab
  4. Click the trash icon to remove the app from that team
  5. Then try to install the app again

With this code you can send a channel message when the Bot enters the channel:

async def on_teams_members_added(  # pylint: disable=unused-argument
    self,
    teams_members_added: [TeamsChannelAccount],
    team_info: TeamInfo,
    turn_context: TurnContext,
):
    for member in teams_members_added:
        if member.id == turn_context.activity.recipient.id and team_info is not None:
            # bot entered a Teams channel
            await turn_context.send_activity("Hello channel! I have just been added.")

Your handler needs to inherit from TeamsActivityHandler.

sf033
  • 107
  • 10
  • do you get a list of all members in the channel this way? how do you create a conversation from that user id? – Joaquín L. Robles Aug 03 '21 at 14:36
  • @JoaquínL.Robles To get the conversation members you may call `roster = await turn_context.adapter.get_conversation_memberts(turn_context)` which will return a `List[ChannelAccount]` – sf033 Aug 04 '21 at 16:20
  • Thanks @sf033 but that would not return the whole team members list (see https://stackoverflow.com/q/68638360/264028) – Joaquín L. Robles Aug 05 '21 at 17:33
  • 1
    @JoaquínL.Robles How my code works: 1) `on_teams_members_added` event 2) `activity.conversation.conversation_type == "channel":` 3) `member_added.id != turn_context.activity.recipient.id` (so the bot has entered the channel) 4) I call `get_conversation_members()` 5) get list of `ChannelAccount`, add them to database (if they dont exist yet). 6) for each (new) user I call `connector_client.conversations.create_conversation(params)` so I get a conversation reference that I can use to send messages to the user proactively. I save this reference in the database. – sf033 Aug 05 '21 at 20:48
  • 1
    @JoaquínL.Robles Word of caution; while I did get this all to work, I eventually gave up on creating Microsoft Teams apps because working with their SDKs is an incredibly painful experience - their whole concept of "turns" sucks and the documentation sucks. It just like every other Microsoft product; best to avoid if you can and use some FOSS alternative. – sf033 Aug 05 '21 at 20:51
  • thanks @sf033 I'll give that a try, I share your feelings abuout MS bro – Joaquín L. Robles Aug 06 '21 at 15:05