This is an Airflow operator that can send cards to MS Teams via webhooks. There are various options to customize the appearance of the cards.
Header, subtitle, and body | Header, subtitle, body, facts, and a button |
---|---|
Body with coloured text and coloured button | Coloured header, body, button, in dark mode |
---|---|
Body and empty green header | Body and coloured header, without logo |
---|---|
Create a webhook to post to Teams. The Webhook needs to be of the PowerAutomate type, not the deprecated Incoming Webhook type. Currently this is done either through the 'workflows' app in Teams, or via PowerAutomate.
Once that's ready, create an HTTP Connection in Airflow with the Webhook URL.
- Conn Type: HTTP
- Host: The URL without the https://
- Schema: https
Copy the ms_teams_power_automate_webhook_operator.py file into your Airflow dags folder and import
it in your DAG code.
The usage can be very basic from just a message, to several parameters including a full card with header, subtitle, body, facts, and a button. There are some style options too.
A very basic message:
op1 = MSTeamsPowerAutomateWebhookOperator(
task_id="send_to_teams",
http_conn_id="msteams_webhook_url",
body_message="DAG **lorem_ipsum** has completed successfully in **localhost**",
)
Add a button:
op1 = MSTeamsPowerAutomateWebhookOperator(
task_id="send_to_teams",
http_conn_id="msteams_webhook_url",
body_message="DAG **lorem_ipsum** has completed successfully in **localhost**",
button_text="View Logs",
button_url="https://example.com",
)
Add a heading and subtitle:
op1 = MSTeamsPowerAutomateWebhookOperator(
task_id="send_to_teams",
http_conn_id="msteams_webhook_url",
heading_title="DAG **lorem_ipsum** has completed successfully",
heading_subtitle="In **localhost**",
body_message="DAG **lorem_ipsum** has completed successfully in **localhost**",
button_text="View Logs",
button_url="https://example.com",
)
Add some colouring — header bar colour, subtle subtitle, body text colour, button colour:
op1 = MSTeamsPowerAutomateWebhookOperator(
task_id="send_to_teams",
http_conn_id="msteams_webhook_url",
header_bar_style="good",
heading_title="DAG **lorem_ipsum** has completed successfully",
heading_subtitle="In **localhost**",
heading_subtitle_subtle=False,
body_message="DAG **lorem_ipsum** has completed successfully in **localhost**",
body_message_color_type="good",
button_text="View Logs",
button_url="https://example.com",
button_style="positive",
)
You can also look at sample_dag.py for an example of how to use this operator in a DAG.
Here are all the parameters that can be set.
Parameter | Values | Notes |
---|---|---|
http_conn_id | The connection ID, eg "msteams_webhook_url" | |
card_width_full | True(default) or False | If false, the card will be the MSTeams default. |
header_bar_show | True(default) or False | If false, heading title, subtitle, logo won't be shown. |
header_bar_style | default , emphasis , good , attention , warning , accent |
docs - style |
heading_title | Limited Markdown support, no monospace |
|
heading_title_size | default , small , medium , large , extraLarge |
docs - size |
heading_subtitle | Appears just below the title, Limited Markdown support, no monospace |
|
heading_subtitle_subtle | True(default) or False | Subtle means toned down to appear less prominent |
heading_show_logo | True(default) or False | |
body_message | Limited Markdown support, no monospace |
|
body_message_color_type | default , dark , light , accent , good , warning , attention |
docs - color |
body_facts_dict | Example: {'aaa':'bbb','ccc':'ddd'} | The key value pairs show up as facts in the card |
button_text | Example: "View Logs" | If not set, button won't be shown |
button_url | Example: "https://example.com" | For example, the URL to the Airflow log |
button_style | default , positive , destructive |
docs - style |
button_show | True(default) or False |
This operator only works with the new PowerAutomate webhooks. The old incoming webhooks were deprecated in this Teams announcement. It says they'll keep working until December 2025 but I expect much degradation in the service before then.
The previous version of this operator, which worked with the old incoming webhooks, is in the master-old-connectors branch. This operator is not a drop-in replacement for the old one, as there are too many differences.
Any simple feature requests, please fork and submit a PR.
I'm using the Airflow Docker Compose, with a few changes. Load examples is false and added an extra_hosts.
Run this to prepare the environment:
mkdir -p ./dags ./logs ./plugins ./config
echo -e "AIRFLOW_UID=$(id -u)" > .env
docker compose up airflow-init
docker compose up
Then wait a bit, and open http://localhost:8080 with airflow:airflow.
To create a connection quickly, use this CLI command, substitute the url bit.
docker compose exec -it airflow-webserver airflow connections add 'msteams_webhook_url' --conn-json '{"conn_type": "http", "description": "", "host": "<url-goes-here-without https://>", "schema": "https", "login": "", "password": null, "port": null }'
Now run the sample_dag to see the operator in action.
To troubleshoot the requests going out, use the included httpecho container which echoes the request to output.
In Airflow connections, create an HTTP Connection to http://httpecho:8081
docker compose exec -it airflow-webserver airflow connections add 'msteams_webhook_url' --conn-json '{"conn_type": "http", "description": "", "host": "httpecho:8081/a/b/c", "schema": "http", "login": "", "password": null, "port": null }'
docker compose logs -f httpecho
Now when you run the sample_dag, you can see the request reflected in the httpecho container.
To manually post the sample card to a webhook URL, just for testing, use the included samplecard.json file.
curl -X POST -H 'Content-Type: application/json' --data-binary @samplecard.json "https://prod-11.westus.logic.azure.com:443/workflows/.............."
Apache 2.0 (see code file headers)