Skip to content

Microsoft Teams

Paid add-on. A card appears in a Teams channel when a submission arrives, when a case is assigned, or when a deadline has passed.

It is the counterpart to the Slack module, for the other half of the market — the one that has Microsoft 365 and never had Slack. Two things, however, are not alike there, and they are the first two sections.

Teams’ incoming webhook no longer exists

Microsoft retired the Office 365 connectors: progressively disabled from 18 to 22 May 2026. Addresses on webhook.office.com or outlook.office.com no longer deliver anything.

The replacement is a Power Automate flow — “Post to a channel when a webhook request is received” — which exposes an address on logic.azure.com. That is the one you paste.

The screen recognises an old connector address and says so in its own words: somebody arriving here has in front of them an address that worked for years, and has to learn that it is Microsoft that retired it, not SolisForms refusing it.

Why not an OAuth application

The plan left the choice “according to the Microsoft mode available”. Posting to a channel through Microsoft Graph requires an application approved by one of the client’s administrators, a ChannelMessage.Send permission, and a Teams application installed in the team so there is an identity to attribute the message to. That is a lot of administration for the same result.

The flow, meanwhile, is created by the person who wants to receive the messages, in their own channel, without going through anybody.

That is this module’s security decision, and the real difference from Slack — where the format is explicit and the module controls it.

Adaptive Cards interprets, in each text block, a subset of Markdown: bold, italic, lists, and links [label](address).

A form value placed there as it is therefore lets a visitor write a clickable link into the client’s internal channel. And not just any channel: the one the team opens precisely in order to read the submissions, and therefore with the trust you grant to what comes from your own form.

It is the same family of danger as Airtable’s typecast or the option created by Notion: the service does something useful by default, and that default becomes a weapon as soon as a stranger holds the keyboard.

The characters that form a link or an emphasis — [, ], *, _, ` — are therefore escaped in everything coming from a submission, as are the double braces that trigger Adaptive Cards’ date functions. A backslash left visible at a client that does not honour the escaping is an annoyance; a phishing link in a team channel is not.

Parentheses are left as they are: they abound in ordinary writing, and a lone parenthesis cannot form a link without the bracket preceding it.

Titles and labels are not escaped: they come from the administrator, who writes their template knowingly and may want bold in it.

Three announcements, each separately switchable

The arrival of a submission, its assignment to somebody, its deadline passed.

A single switch would have forced a choice between noise and silence: a team handling cases wants to know that a case has been assigned to it without receiving the month’s three hundred submissions. Another wants the opposite.

Each announcement has its own tracking row: UNIQUE (entry_id, kind). A key carrying the submission alone would have forced a choice between overwriting the state of the previous announcements and posting twice in the channel.

The form’s condition applies only to a submission’s announcement. An assignment and a deadline are team gestures, decided after the fact, and filtering them on the form’s values would make the announcement disappear for a case somebody has just been entrusted with.

The last two depend on the internal processing module, which now emits solis_forms_pro_workflow_assigned and solis_forms_pro_workflow_overdue. The first is emitted independently of the email-sending setting: a team may want the announcement in its channel without wanting the individual message.

A dead address suspends the connector

That is what the plan asks for, and it is this module’s particularity.

A deleted flow or a renewed address answers 401, 403 or 404. No retry will change anything. Without a guard, every submission would set off for three attempts, and the log would fill with the same refusal until somebody noticed — which is to say for a long time, since the symptom is silence.

The connector therefore suspends itself at the first definitive refusal. Nothing more is scheduled, the screen writes it large, and resuming reschedules what had failed: otherwise the suspension would have cost exactly what it claimed to avoid, announcements lost without anybody knowing.

Putting in a fresh address lifts the suspension: that is precisely the gesture it was waiting for.

The address is the authorisation

There is neither an id nor a token: whoever holds the flow’s address can post in the channel. It is therefore encrypted at rest, never redisplayed — only its last twelve characters are shown, enough to tell two flows apart, too little to reconstruct this one — and checked against the .logic.azure.com suffix, the leading dot separating a Microsoft flow from an attacker-logic.azure.com.

Nor does it go into the delivery log.

The test really posts

The button sends a card into the channel. That is deliberate: an address that answers is not an address that posts — a flow can accept the request and do nothing with the body. The only proof is a message appearing, and that is what you come looking for when you click.

The card

A title, the fields designated one by one, and a button to the submission’s admin screen.

The title is prefixed by the nature of the announcement — “New submission”, “Assigned”, “Overdue” — and that prefix is not configurable: it is what lets you tell a submission from an overdue case at a glance, in a channel.

The fields are designated one by one, never “every value”: a team channel is read by people who are not all recipients of all the data. Sensitive types are set aside whatever happens.

The link leads to the admin screen, which always requires a session: received by mistake, it discloses nothing, and it avoids copying into the channel what the screen already shows.

The payload is bounded at two levels: each value to five hundred characters, the number of fields to twenty. The heaviest card the module can compose therefore stays well below the limit Teams accepts — the client’s guard is a belt, not the clothing.

What is not attempted, and what is retried

Nothing is scheduled without an address, without a ticked announcement, if the connector is suspended, or if the form’s condition is not met. A submission marked as spam or sent to the trash does not go out.

429 and 5xx are replayed, at 1, 5 then 30 minutes. 401, 403 and 404 are not: they suspend.

A Teams outage never blocks the submission. It is recorded, confirmed to the visitor and notified by email before this module is called on.

Schema

slf_teams_messages: one row per submission and per nature of announcement, with the state, the reason for the last problem and the number of attempts.

There is no remote message id: a Power Automate flow does not return that of the message it posted, and the module never modifies or deletes it. Keeping an empty column would have suggested that one day we would know what to do with it.

The address lives in an option, encrypted. The suspension date and its reason are not: they are not secrets, and reading them in clear is precisely what you want when looking for why a channel has gone silent.

What V1 does not do

No interactive card, no reply, no team creation, no reading of conversations, no file.

Actionable cards are not, as it happens, supported by the flows’ webhook trigger: what the old connector allowed, the new one does not. The card’s button therefore opens a page, and does nothing else.