Teams proactive message HTTP 403s resolved
The Teams integration now properly forwards tenant and user identity metadata on proactive (bot-initiated) messages, fixing a regression that blocked cron announces and scheduled notifications with HTTP 403 errors.
Proactive messages sent by the Teams bot were failing silently with HTTP 403 errors, blocking scheduled announcements and cron-based notifications from reaching users. The Bot Framework connector requires tenant and user identity metadata—tenantId and aadObjectId—on outbound activities to route them correctly, but this information was being discarded during inbound processing, so when the system tried to send proactively, the connector rejected the request.
The fix captures these fields at inbound time: tenantId is extracted from channelData.tenant.id (the canonical source for channel activities, where conversation.tenantId is often unset), and aadObjectId is pulled from activity.from. Both are stored on the conversation reference and forwarded on every outbound proactive send.
The change applies across the message pipeline—in the message handler that processes inbound activities, in the merge logic that preserves values on sparse activities like conversationUpdate, in the conversation reference builder that prepares outbound requests, and in the Bot Framework connector layer that makes the actual HTTP call.
Previously working configurations broke after upgrading from v2026.3.23-2 to v2026.3.31. All 583 tests in the Teams suite pass.
View Original GitHub Description
Summary
Fixes HTTP 403 on proactive Teams messages by capturing tenantId and aadObjectId from inbound activities and forwarding them on outbound proactive sends.
Root cause
The Bot Framework's connector requires tenantId and aadObjectId in the conversation reference for proactive (bot-initiated) sends. The msteams plugin was discarding these from inbound activities, so when cron / scheduled messages tried to send proactively, the resulting connector request was rejected with 403.
Fix
- Extract
tenantIdfromactivity.channelData?.tenant?.idat inbound time (channel activities often leaveconversation.tenantIdunset, sochannelData.tenant.idis the canonical source) - Extract
aadObjectIdfromactivity.from?.aadObjectIdat inbound time - Store both on
StoredConversationReference - Forward them on outbound proactive sends in
messenger.tsand on the Bot Framework connector request insdk.ts(viachannelData.tenant.id,conversation.tenantId, andrecipient.aadObjectId)
Fixes #58774
Test plan
- Unit tests for inbound capture (channel activity with
channelData.tenant.id, plus graceful degradation whenchannelDatais missing) - Unit tests for outbound forwarding via
buildConversationReferenceandsendMSTeamsMessages - Full msteams suite passes (583 tests)
- Manual: trigger a cron announce to a Teams channel and verify it succeeds