1+ import json
12from datetime import datetime , timezone
23from http import HTTPStatus
3- from typing import Any , Optional
4+ from typing import Any , Dict , List , Optional
45
56import requests
67from ratelimit import limits , sleep_and_retry
2526
2627Channel : TypeAlias = Optional [str ]
2728ONE_SECOND = 1
29+ TEAMS_PAYLOAD_SIZE_LIMIT = 27 * 1024
2830
2931
3032class TeamsWebhookHttpError (MessagingIntegrationError ):
@@ -36,8 +38,8 @@ def __init__(self, response: requests.Response):
3638 )
3739
3840
39- def send_adaptive_card ( webhook_url : str , card : dict ) -> requests . Response :
40- payload = {
41+ def _build_payload ( card : dict ) -> dict :
42+ return {
4143 "type" : "message" ,
4244 "attachments" : [
4345 {
@@ -48,6 +50,60 @@ def send_adaptive_card(webhook_url: str, card: dict) -> requests.Response:
4850 ],
4951 }
5052
53+
54+ def _truncation_notice_item () -> Dict [str , Any ]:
55+ return {
56+ "type" : "TextBlock" ,
57+ "text" : "_... Content truncated due to message size limits._" ,
58+ "wrap" : True ,
59+ "isSubtle" : True ,
60+ }
61+
62+
63+ def _minimal_card (card : dict ) -> dict :
64+ return {
65+ ** card ,
66+ "body" : [
67+ {
68+ "type" : "TextBlock" ,
69+ "text" : "Alert content too large to display in Teams." ,
70+ "wrap" : True ,
71+ "weight" : "bolder" ,
72+ }
73+ ],
74+ }
75+
76+
77+ def _truncate_card (card : dict ) -> dict :
78+ body : List [Dict [str , Any ]] = list (card .get ("body" , []))
79+ if not body :
80+ return card
81+
82+ while len (body ) > 1 :
83+ payload = _build_payload ({** card , "body" : body + [_truncation_notice_item ()]})
84+ if len (json .dumps (payload )) <= TEAMS_PAYLOAD_SIZE_LIMIT :
85+ break
86+ body .pop ()
87+
88+ truncated = {** card , "body" : body + [_truncation_notice_item ()]}
89+ if len (json .dumps (_build_payload (truncated ))) > TEAMS_PAYLOAD_SIZE_LIMIT :
90+ return _minimal_card (card )
91+ return truncated
92+
93+
94+ def send_adaptive_card (webhook_url : str , card : dict ) -> requests .Response :
95+ payload = _build_payload (card )
96+ payload_json = json .dumps (payload )
97+ if len (payload_json ) > TEAMS_PAYLOAD_SIZE_LIMIT :
98+ logger .warning (
99+ "Teams webhook payload size (%d bytes) exceeds limit (%d bytes), "
100+ "truncating card body" ,
101+ len (payload_json ),
102+ TEAMS_PAYLOAD_SIZE_LIMIT ,
103+ )
104+ card = _truncate_card (card )
105+ payload = _build_payload (card )
106+
51107 response = requests .post (
52108 webhook_url ,
53109 json = payload ,
0 commit comments