rveachkc / pymsteams

Format messages and post to Microsoft Teams.
https://pypi.org/project/pymsteams/
Apache License 2.0
418 stars 77 forks source link

Deprecation warning in MS Teams #155

Open rderooy opened 2 weeks ago

rderooy commented 2 weeks ago

Describe the bug I guess the writing is on the wall for this project. As of yesterday we started getting deprecation warnings that the teams webhook is going away and we need to migrate to MS Power Automate. The existing webhooks (O365 connectors) will only work until October 1st, so this is a rather short time to migrate, especially with the summer vacations just starting.

It also seems that we may need MS Power Automate Premium for integration with Teams, for which you obviously need to pay a per user per month fee.

I had a quick look around for something similar to pymsteams for MS Power Automate, but could not find anything. I found this guide that shows to use http post operations, which is a rather poor replacement: https://medium.com/@ronaldoscardini/how-to-integrate-your-python-automations-with-ms-power-automate-55e5d2a6c7a0

If someone found some additional information, please add it here.

calcium90 commented 2 weeks ago

Unfortunately for us we just configured a load of O365 connector webhooks as we just migrated to Teams. Sure enough as soon as we're done they're being deprecated. So I was looking at using Workflows instead, I've tried to use pymsteams against a newly configured Workflow in Teams, with these settings:

Workflow Step 1

Workflow Step 2 Apply To Each

I had misplaced optimism assuming they'd just accept the same format as before since it's worded as 'When a Teams webhook request is received'. Unfortunately and perhaps predictably it errors when I try posting a card to the new webhook using pymsteams: Unable to process template language expressions for action 'Apply_to_each' at line '0' and column '0': 'The template language expression 'triggerBody()['attachments']' cannot be evaluated because property 'attachments' doesn't exist, available properties are 'text'. Please see https://aka.ms/logicexpressions for usage details.'. Based on the documentation, the required payload format for a webhook created in a Workflow is as below, with each card being in an array of attachments:

{
       "type":"message",
       "attachments":[
          {
             "contentType":"application/vnd.microsoft.card.adaptive",
             "contentUrl":null,
             "content":{
                "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
                "type":"AdaptiveCard",
                "version":"1.2",
                "body":[
                    {
                    "type": "TextBlock",
                    "text": "For Samples and Templates, see [https://adaptivecards.io/samples](https://adaptivecards.io/samples)"
                    }
                ]
             }
          }
       ]
    }
The properties for Adaptive Card JSON file are as follows:

The "type" field must be "message".
The "attachments" array contains a set of card objects.
The "contentType" field must be set to Adaptive Card type.
The "content" object is the card formatted in JSON.

So I'm guessing one option would be for pymsteams to support this format, optionally initially but then default when Microsoft disables O365 connector webhooks in October?

mephinet commented 2 weeks ago

Tested your approach: works for me, as long as you don't increase the "version" to 1.5. 1.4 is OK.

doranko commented 2 weeks ago

As a workaround, I currently use triggerBody()?['text'] instead of triggerBody()['attachments'] in the workflow. This works as expected for now.

However, since HTTP status 202 is returned, pymsteams throws a TeamsWebhookException, so error handling is required.

calcium90 commented 2 weeks ago

As a workaround, I currently use triggerBody()?['text'] instead of triggerBody()['attachments'] in the workflow. This works as expected for now.

However, since HTTP status 202 is returned, pymsteams throws a TeamsWebhookException, so error handling is required.

Thanks for that, yes that also works for me with simple cards like card.text("hello world") where everything is in 'text', I haven't yet tried getting it to work with a card with sections though, ie:

        card = pymsteams.connectorcard(self.webhook_uri)
        card_section = pymsteams.cardsection()
        card_section.title("Some Section")
        card_section.text("Some message)
        card.addSection(card_section)
carlgevans commented 2 weeks ago

Like this?

image

We use Teams webhooks via pymsteams all over the place, so this deprecation by MS is really frustrating.

calcium90 commented 2 weeks ago

Like this?

image

We use Teams webhooks via pymsteams all over the place, so this deprecation by MS is really frustrating.

I ended up doing it as a 'Post message in a chat or channel' rather than a Card, like this: image

A bigger issue we've found is that it seems 'Flow bot' cannot post to Private (or apparently Shared) channels. A good portion of our channels are Private or Shared so I'm not sure what the solution is for this.

ALERTua commented 2 weeks ago

Yeah, the plain text way works, but I wish there was a way to compose a card with fact blocks :( I still cannot get an AdaptiveCard to be displayed correctly. I only get "We're sorry, this card couldn't be displayed" :(

rveachkc commented 2 weeks ago

I will try to allow a 202 error code today, I'll need to do a bit more research on this before making any decisions going forward.

Krisscut commented 2 weeks ago

A colleague pushed a repo here https://github.com/AeroFlorian/MsTeamsAdaptiveCard which shows how to use adaptive cards to have similar functionality, maybe a similar thing could be done in the underlying code of pymsteams to recover the sections/facts etc.

The readme explains how to configure the workflow and there are examples of various json and their output. I hope this can help with your research/migration

kylejtuck commented 1 week ago

This is probably not the best approach, but it is at least a workaround for my most critical use.

My Power Automate workflow is:

The messageText variable is set with: replace(triggerBody()?['text'], '"', '\"')

Not a great way to prep the text for use in the JSON field below, but I have not yet found a better way in Power Automate.

Then in the Adaptive Card field, I used:

{
    "$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
    "type":"AdaptiveCard",
    "version":"1.2",
    "body":[
      {
      "type": "TextBlock",
      "size": "medium",
      "weight": "bolder",
      "text": "@{triggerBody()?['title']}",
      "color": "attention",
      "style": "heading",
      "wrap": true
      },{
      "type": "TextBlock",
      "text": "@{variables('messageText')}",
      "wrap": true
      }
    ]
}

This did let me at least continue using the title and text values I was trying to send.

I know it's not the fault of this project or its maintainer; just a rant about MS. This whole Power Automate flow requirement is pure nonsense and adds way more complexity than is necessary. Not really sure what they're trying to solve.

rveachkc commented 1 week ago

I've not really had a chance to look at this until today, but I too have a bunch of work to migrate notifications on our systems to the new automate platform.

At the current moment, my organization has the new power automate workflow blocked, but I'm sure that can be done.

I'd really like to have access and play around with it some before deciding what to do. The screenshots I have seen so far show what appears to be some kind of template design format, and I'm hesitant to go the direction of requiring a specific template or re-working a new adaptive card library. Who knows, it's still early.

I did get an update in to allow for all return codes 200 <= x < 300.

carlgevans commented 1 week ago

They could do with extending the deadline from August 15th to give us all time to implement the changes (and hopefully your updated library @rveachkc :-) ). Probably worth us all raising it with MS.

Looks like there is a feedback petition to stop the retirement.. https://feedbackportal.microsoft.com/feedback/idea/80ed6877-b642-ef11-b4ad-000d3a7aba8b

ALERTua commented 4 days ago

I have created an MSTeams Wrapper for AdaptiveCards for Python 2 and 3 from scratch on pure Python https://github.com/ALERTua/msteamsapi pypi module done https://pypi.org/project/msteamsapi/

bbenouarets commented 2 days ago

If other system administrators are having difficulties locating the affected teams: I have written a small tool in Golang that uses the Graph API to output the affected teams.

Teams Webhook Finder

This has helped us enormously, as Microsoft does not offer its own solution for reading the affected channels and teams. We have over 350 teams in our company, which we would otherwise have had to search through manually.