Open xolf opened 2 months ago
I tried creating a "workflow" as indicated in the message, and using the URL provided but it doesn't seem to work.
I tried creating a "workflow" as indicated in the message, and using the URL provided but it doesn't seem to work.
I did the same and am getting a 400 Rad Request
response with nothing else as to the cause.
Same here. The integrated Workflow in Teams didn't worked for me. I created a Power Automate Flow with an HTTP Endpoint (requires Premium subscription) and then send the messages via the Microsoft Teams connector to Teams.
One benefit of this solution is, you can also target individual users or group chats, in addition to channels.
I have done some research, it looks like Microsoft has changed the format of the payload - So I think some changes will need to be made to the code.
I have been doing some research on this, the new 'workflow' way is not very well documented. I have managed to get a JSON webhook to create an 'AdaptiveCard'.
The tricky part is getting the workflow setup correctly.
First head into teams and create a new workflow, start a blank workflow. For the trigger, you want to search for webhook and select the Microsoft Teams Webhook.
Next add a step to the workflow, it should look like this so far:
Now search for "Apply to each" and select it as an action. In the "Select an output" box you want to choose the dynamic content from the righthand side, select "Attachments". It should now look like this:
Next add another action and find "Post card in chat or channel" and fill in the details for your required destination. (Make sure you choose the correct "Post as" option as flow bots cannot post into private channels).
You should now have something like this:
Now in the adaptive chat box you need to create an "expression" and in the expression you need to put the following "item().content". It should look like the following:
Hit okay on the expression and it will put it into the adaptive card box, then save the workflow.
Once saved you can click on the webhook trigger at the top and copy the webhook url.
Now send a POST request to the webhook with the JSON below
{ "attachments": [ { "contentType": "application/vnd.microsoft.card.adaptive", "contentUrl": null, "type": "AdaptiveCard", "content": { "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.2", "body": [ { "type": "TextBlock", "wrap": true, "text": "This is the text of a card" } ], "actions": [ { "type": "Action.OpenUrl", "title": "Github URL", "url": "https://github.com" } ] } } ] }
If you format the JSON you will see that there is an attachments
array and the attachment has a content
object. This content
object is a valid schema for AdaptiveCards.io. You can view the schema here: AdaptiveCards.io.
I know this does not currently fix the issue with the package however it gives a good head start to someone wanting to create a PR. If I can get around to it, I will work on the PR myself.
If anyone needs anymore info, please let me know.
@jsandfordhughescoop awesome tutorial. I was able to build the workflow as you describe and get your test POST request to show the card in the Teams channel.
I could not get the older MessageCard (that is built in the class \NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage
) to work through this.
Has anyone used this repo before? https://github.com/sebbmeyer/php-microsoft-teams-connector
It has a class that builds the AdaptiveCard schema and also a way to send it to a Teams webhook endpoint. I like using the Laravel Notification system for things like this, but what would be the chances of a PR using sebbmeyer/php-microsoft-teams-connector
to be merged into this repo?
Looks like maybe @Tob0t is the main maintainer of this repo. @Tob0t do you have an opinion on expanding this package to handle the AdaptiveCard schema?
Just a note that Message Cards are marked as Legacy in the Microsoft documentation
https://learn.microsoft.com/en-us/outlook/actionable-messages/message-card-reference
So any idea if the workflow is disabled on our organization? any alternatives?
So any idea if the workflow is disabled on our organization? any alternatives?
A quick google and it does not seem disabling workflows is an option in Azure / teams admin
@jsandfordhughescoop
Thats interesting! Sorry nothing came up in a google search. As far as I am aware, teams are EOL all "connectors" so the only way going forward are workflows.
Maybe chat to your admins and see what they can do?
Thats interesting! Sorry nothing came up in a google search. As far as I am aware, teams are EOL all "connectors" so the only way going forward are workflows.
Maybe chat to your admins and see what they can do?
thanks @jsandfordhughescoop
i will reach to them.
Thats interesting! Sorry nothing came up in a google search. As far as I am aware, teams are EOL all "connectors" so the only way going forward are workflows. Maybe chat to your admins and see what they can do?
thanks @jsandfordhughescoop
i will reach to them.
@jglagrimas Your organisation looks like they have set up conditional access to the Power Automate Workflows - hence why you are seeing it as disabled by the orgainisation.
I have a current working workarround. Create a new class to extend MicrosoftTeamsMessage:
<?php
namespace App\Services\MicrosoftTeams;
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
class TeamsNotification extends MicrosoftTeamsMessage
{
protected $payload = [];
protected string $type = "Good";
/** @var string webhook url of recipient. */
protected $webhookUrl = null;
public function __construct()
{
parent::__construct();
$this->payload = [
"\$schema" => "https://adaptivecards.io/schemas/adaptive-card.json",
"type" => "AdaptiveCard",
"version" => "1.0",
];
}
public static function create(string $content = ''): self
{
return new self();
}
public function title(string $title, array $params = []): self
{
$this->payload["body"][] = [
"type" => "TextBlock",
"wrap" => true,
"style" => "heading",
"text" => $title,
"weight" => "bolder",
"size" => "large",
];
return $this;
}
public function type(string $type): self
{
$types = ["info" => "Good", "error" => "Attention", "warning" => "Warning", "success" => "Good"];
$this->type = $types[$type];
return $this;
}
/**
* @throws \Exception
*/
public function to(?string $webhookUrl): self
{
if (!$webhookUrl) {
throw new \Exception("Webhook url is required. Tried to send a teams notification without a webhook url.");
}
$this->webhookUrl = $webhookUrl;
return $this;
}
public function content(string $content, array $params = []): self
{
// add the content as a new text block
$this->payload["body"][] = [
"type" => "TextBlock",
"wrap" => true,
"text" => $content,
"size" => "medium",
"separator" => true,
];
return $this;
}
public function button(string $text, string $url = '', array $params = []): self
{
$this->payload["actions"][] = [
"type" => "Action.OpenUrl",
"title" => $text,
"url" => $url,
"style" => "positive",
];
return $this;
}
public function addStartGroupToSection($sectionId = 'standard_section'): self
{
return $this;
}
public function fact(string $name, string $value, $sectionId = 'standard_section'): self
{
$factset = collect($this->payload['body'])->filter(function ($item) {
return $item['type'] === "FactSet";
});
if($factset->isEmpty()) {
$factset = [
"type" => "FactSet",
"facts" => [],
];
}
$factset['facts'][] = [
"title" => $name,
"value" => $value,
];
$this->payload['body'][] = $factset;
return $this;
}
public function getWebhookUrl(): string
{
info("Sending to teams wb: $this->webhookUrl");
return $this->webhookUrl;
}
public function toArray(): array
{
// check and get the first text block and set the color to the type
if($this->payload["body"][0] && $this->payload["body"][0]["type"] === "TextBlock") {
$this->payload["body"][0]["color"] = $this->type;
}
return $this->payload;
}
}
And now, instead of:
return MicrosoftTeamsMessage::create()
->to(config('services.microsoft_teams.sales_url'))
->type('success')
->title('Subscription Created')
->content('Yey, you got a **new subscription**. Maybe you want to contact him if he needs any support?')
->button('Check User', 'https://foo.bar/users/123');
Do this:
return TeamsNotification::create()
->to(config('services.microsoft_teams.sales_url'))
->type('success')
->title('Subscription Created')
->content('Yey, you got a **new subscription**. Maybe you want to contact him if he needs any support?')
->button('Check User', 'https://foo.bar/users/123');
For creating a new workflow in teams:
Go to teams -> click on the three dots on the left side and select workflows>
In the "Adaptive Card" field, make sure to choose expression and use triggerBody() as value.
Ok, so it seems that we've all been granted a reprieve by Microsoft from August 2024 until December 2025 (although we'll have to make a URL change in December 2024 to opt-in). But long-term, it certainly sounds like the Webhook to Workflow pathway is going to be the only option for sending notifications to Teams. And that will in turn probably require the Adaptive Card format. More info here: https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/
In terms of a way forwards for the Notification Channel driver approach (this package) we can take inspiration from a couple of packages that have leaned into the Workflow pattern (and Adaptive Cards): https://github.com/osa-eg/laravel-teams-notification https://github.com/sebbmeyer/php-microsoft-teams-connector/
Hi, sorry for the late response 🙈 Since I am no longer actively using teams, I could not find (free)time to migrate to prepare an alternative method. I have no strong opinion towards which way to go, but I am open to suggestions (or even better, a PR ;)) This package is open source, so feel free to create a PR - I am willing to review and merge it if it is a satisfying solution.
Hey,
since today Teams appends the following messages automatically to messages send via this package:
Are there any guides or tips for an migration?