How messages are delivered
What a bridged message looks like on each platform, how loops are prevented, and what is not relayed.
A relayed message is a new message posted by the ThreadBridge app on the destination platform, carrying the original author's name. It is not the same message moved across, and it can't be: the two platforms have no shared notion of a message or a person.
What it looks like
Teams → Slack. The message is posted under the original author's name, with the name repeated at the start of the text:
Dana Okafor
*Dana Okafor:* can we push the review to Thursday?
Slack → Teams. The message arrives with the author's name in bold:
<b>Dana Okafor:</b> can we push the review to Thursday?
Slack identifies an author by ID rather than by name, so ThreadBridge looks the name up once and caches it. A name that can't be resolved (a revoked token, a Slack outage) is never a reason to hold a message: it relays without the prefix instead.
Formatting is normalized to plain text on the way in, so Teams HTML doesn't leak into
Slack. Teams @mentions arrive as @Name text; they read
correctly but don't notify anyone on the far side, because there's no account there to
notify.
Timing
Both platforms push to ThreadBridge over webhooks rather than being polled, so delivery is normally a second or two. Teams notifications sometimes carry only a pointer to the message, in which case the runtime fetches the body before relaying it, a little slower, same result.
Loop prevention
A relayed message lands in a channel the bridge is also watching, which is exactly the shape of an infinite loop. ThreadBridge prevents it deliberately rather than hoping bot flags are enough:
- Before sending, the runtime records a fingerprint (a hash of the bridge, destination channel, text, and sender) of the echo it expects to see.
- When that echo arrives, the fingerprint matches, the entry is consumed, and the message is dropped instead of being relayed back.
- Fingerprints expire after thirty seconds. They exist only in the runtime's memory and are never written to a database.
Duplicate webhook deliveries, which both platforms do occasionally, are also caught, because the runtime keeps a mapping between the platforms' IDs for each message it has already handled. That mapping is persisted, so it survives a restart or deploy instead of being rebuilt from scratch: a message relayed just before a deploy is still recognized as already-handled afterward.
When one side is unreachable
A bridge can carry several channel pairs, and each destination is attempted independently. If Teams rejects a post, the Slack side of the same message still goes through, and the failure is recorded rather than silently swallowed.
Limits worth knowing
- Edits and deletions aren't relayed. Correcting a message means posting a correction.
- Threads carry across one level deep. A reply in a Slack thread lands as a reply to the matching Teams message, and a Teams reply lands in the matching Slack thread. If the message being replied to was never relayed (it was posted before the bridge started, for example), the reply arrives as a new top-level message instead.
- Reactions, files, and images aren't relayed. Share a link if the other side needs the file.
- Messages posted before a bridge started aren't backfilled.
- Messages posted by other bots and apps aren't relayed; only messages from people.