Tag people in MS Teams alert

Hi everybody,
I want to tag people, when I send alert to Msteam. I cannot find any document of grafana for this.
Please help me!

Thanks.

Hi, @tieungao88

I managed to mention people by using the following within a template:

someone@example.com


Here is a short version of my template, in case it helps:

{{ define “RMQ.Queue.Message” }}
{{ if .Alerts.Firing -}}
Alerting Queue Details:
{{- range .Alerts.Firing }}

Queue Name: {{ .Labels.queue}}
Check this out: someone@example.com

{{ if .SilenceURL }}
[Silence here]({{ .SilenceURL }})
{{ end }}
{{ if .DashboardURL -}}
Go to dashboard: {{ .DashboardURL }}
{{ end }}
{{ end }}
{{- end }}

I think you need to find MS Team doc/example first, e.g. Sending message with atmention onto a channel using GraphAPI .. and replying it – Vesa Nopanen – My Metaverse Day

So then you need to find if you can get all user details and if you can add it to custom Grafana MS Team notification template.

Didn’t realize the markdown would make the email clickable.
I was using:
< a t> “name-goes-here”@“somedomain” </ a t> (without spaces and quotes)

Hi I have the same problem, I can’t tag a person or a group in a teams channel (created via a webbook)
I need a template to integrate into the alert contact point please, and the exact place where I will put the template (json for example)

Hey @flaviusluca
Sorry to mention but have to ask, so you just add:

Someone: <at>email@domain.com</at>

Without any other changes in anything?

if so, I can’t get it to work! can you please share more?

Hey, @mohamadkh75

Don’t worry at all for the tag and I’m really sorry it didn’t work for you.

Let me give you a bit more details so that you and other people can reproduce it.

I know the RabbitMQ bit is not related to this issue, but I’ll explain it regardless so that people will have the whole picture and understand how the pieces work together.

I’m using Grafana v11.3.1 (9225f4a1cb) - should work with the previous versions too. Some configs might be found under different names/sections though.

1. Alert rule configuration
In the alert rule settings, under the Configure notification message the setup I have is as follows:

Alert Config

2. Contact Point
The Contact Point I defined is configured as below:

Contact Point Config

Notice that I’ve used templates for Title and for the Message as highlighted above.

3. Title template
Nothing fancy here:

Title Template

4. Message template
This defines how the message is structured.

Message template - picture

Message Template - code

{{/* print_alert local template /}}
{{ define “print_alert” -}}
[{{.Status}}] {{ .Labels.alertname }}
{{/
Labels: - all the labels that come from the Rule */}}
{{ range .Labels.SortedPairs -}}
{{if eq .Name “queue” -}}
Queue: {{ .Value }}
{{end -}}
{{ end }}
{{ range .Labels.SortedPairs -}}
{{ if eq .Name “rmq_env” -}}
Environment: {{ .Value }}
{{end -}}
{{ end -}}

{{/* Annotations: - whatever comes from the Rule in the Summary and annotations section*/}}
{{ if .Annotations }}
{{ range .Annotations.SortedPairs }}
{{ .Name }}: {{ .Value }}
{{ end }}
{{ end }}

Admin UI: [https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}}](https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}})

{{ if .SilenceURL }}
[Silence here]({{ .SilenceURL }})
{{ end }}
{{ if .DashboardURL -}}
Go to dashboard: [Dashboard]({{ .DashboardURL }})
{{ end }}
{{ end }}

{{/main template which gives the name of the template - also used in the Contact point/}}
{{ define “RabbitMq.Published.Template” -}}
{{ if .Alerts.Firing -}}
{{ len .Alerts.Firing }} firing alerts:
{{ range .Alerts.Firing }}
{{ template “print_alert” . }}
{{ end }}
{{ end }}
{{ if .Alerts.Resolved -}}
{{ len .Alerts.Resolved }} resolved alerts:
{{ range .Alerts.Resolved }}
{{ template “print_alert” .}}
{{ end -}}
{{ end }}
{{- end }}

Bellow are some explanations for most of the bits in the template.

4.1 “Main Template” - defined at the bottom

Main Template Code

{{/main template which gives the name of the template - also used in the Contact point/}}
{{ define “RabbitMq.Published.Template” -}}
{{ if .Alerts.Firing -}}
{{ len .Alerts.Firing }} firing alerts:
{{ range .Alerts.Firing }}
{{ template “print_alert” . }}
{{ end }}
{{ end }}
{{ if .Alerts.Resolved -}}
{{ len .Alerts.Resolved }} resolved alerts:
{{ range .Alerts.Resolved }}
{{ template “print_alert” .}}
{{ end -}}
{{ end }}
{{- end }}

Basically defines how the Firing and Resolved messages should look like.
In both cases is specified to use a “local” (think of it like a method/function) defined template: the print_alert template.

4.2 “Print Alert Template” - defined at the top

This is most probably not efficient code. Feel free to improve it.

Print Alert Template

{{/* print_alert local template /}}
{{ define “print_alert” -}}
[{{.Status}}] {{ .Labels.alertname }}
{{/
Labels: - all the labels that come from the Rule */}}
{{ range .Labels.SortedPairs -}}
{{if eq .Name “queue” -}}
Queue: {{ .Value }}
{{end -}}
{{ end }}
{{ range .Labels.SortedPairs -}}
{{ if eq .Name “rmq_env” -}}
Environment: {{ .Value }}
{{end -}}
{{ end -}}

{{/* Annotations: - whatever comes from the Rule in the Summary and annotations section*/}}
{{ if .Annotations }}
{{ range .Annotations.SortedPairs }}
{{ .Name }}: {{ .Value }}
{{ end }}
{{ end }}

Admin UI: [https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}}](https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}})

{{ if .SilenceURL }}
[Silence here]({{ .SilenceURL }})
{{ end }}
{{ if .DashboardURL -}}
Go to dashboard: [Dashboard]({{ .DashboardURL }})
{{ end }}
{{ end }}

:red_exclamation_mark:Note
queue and rmq_env are labels that come from the RMQ scrapped metrics (i.e. I haven’t defined them in the rule).

The Flow:

  • {{ range .Labels.SortedPairs -}} - iterates through the labels.
    If label name is queue: {{if eq .Name "queue" -}} or rmq_env: {{ if eq .Name "rmq_env" -}} print their value.

  • {{ if .Annotations }} - check if there are any annotations defined.
    In our case, Check this out: annotation was defined in the Alert Rule, with the <at>someone@domain</at> as value.

  • {{ range .Annotations.SortedPairs }} **{{ .Name }}**: {{ .Value }} - iterate through each annotation and print the Annotation Name in bold and it’s value.

  • **Admin UI**: [https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}}](https://{{ .Labels.env}}-{{ .Labels.rmq_env}}.rabbit-management-UI:15671/#/queues/%2F/{{ .Labels.queue}}) - this defines a link to the RabbitMQ Management UI that I can click from the notification.

  • {{ if .SilenceURL }} [Silence here]({{ .SilenceURL }}) {{ end }} - prints the silence URL from where the Alert can be silenced.

  • {{ if .DashboardURL -}} Go to dashboard: [Dashboard]({{ .DashboardURL }}) {{ end }} - prints the Dashboard URL, if the Alert was linked to a Dashboard.

This how a Firing Alert looks like:
Note that I removed some personal information

Because the message is quite lengthy already, I purposely omitted how to Alert, Contact Point and Notification Policies are linked together. I can show how I did that too, if needed. Just let me know.

Hope this is a bit more clear now, but if not, please let me know. Cheers

2 Likes

hey, @dkhiliahmed77

I added more details on how I managed to get it working in a Reply to @mohamadkh75 comment.
Please have a look there and let me know if you still have issues.

1 Like

Hey @flaviusluca

One important point is that i must use “Workflows” instead of “Incoming Webhook” in order to make this work!

It’s working now :slight_smile:

Thanks for your help!

1 Like

hey, @mohamadkh75

Happy that you got it working and that my notes were helpful.

Take care!

hey @flaviusluca . If it would be possible, can you share the Workflow configuration as well? I followed some of your steps for mentioning a user, but when using the old Webhook it will just post out a plain text with the user’s email and won’t mention him.

Hey @dardlubishtani
Sorry for the late reply.

The Workflow I use is: Send webhook alerts to a channel. (make sure you have a Team and a channel configured)

You can configure the Workflow as follows:

  1. In Teams, go to Apps
  2. Then search for webhook
  3. Expand Workflows drop-down (if collapsed) → All templates
  4. Select Send webhook alerts to a channel
  5. Type a Name for the Workflow → Next
  6. Select a Team and a Channel → Add Workflow
  7. Copy the generated URL → Done
  8. Use it as Contact points’ URL in Grafana Alert
    :red_exclamation_mark:Use the templates defined in the initial comment for the Alert’s Title and Message





Hope you’ll get it working now.
Take care

2 Likes

Hey man,
I managed to get it fixed somehow by first parsing JSON, composing and in the end posting a card to teams channel. Basically my flow is like this:

  • When a Teams webhook request is received
  • Parse JSON
  • Compose
  • Post card in a chat or channel.

Your article has been a great help. Thank you!

1 Like

Hey
Happy the article helped and that you managed to get it working.

Feel free to post more details of your solution, if you want to share it with the community.

Take care

Parse JSON step:

  • Content: triggerBody()?[‘attachments’]
  • Schema:
{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "content": {
                "type": "object",
                "properties": {
                    "body": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "type": {
                                    "type": "string"
                                },
                                "text": {
                                    "type": "string"
                                },
                                "color": {
                                    "type": "string"
                                },
                                "size": {
                                    "type": "string"
                                },
                                "weight": {
                                    "type": "string"
                                },
                                "wrap": {
                                    "type": "boolean"
                                },
                                "actions": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "properties": {
                                            "type": {
                                                "type": "string"
                                            },
                                            "title": {
                                                "type": "string"
                                            },
                                            "url": {
                                                "type": "string"
                                            }
                                        },
                                        "required": [
                                            "type",
                                            "title",
                                            "url"
                                        ]
                                    }
                                }
                            },
                            "required": [
                                "type"
                            ]
                        }
                    },
                    "$schema": {
                        "type": "string"
                    },
                    "type": {
                        "type": "string"
                    },
                    "version": {
                        "type": "string"
                    },
                    "msTeams": {
                        "type": "object",
                        "properties": {
                            "width": {
                                "type": "string"
                            }
                        }
                    }
                }
            },
            "contentType": {
                "type": "string"
            }
        },
        "required": [
            "content",
            "contentType"
        ]
    }
}

Compose step(first text block is for my title template and second for my message body template):

{
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "msTeams": {
    "width": "Full"
  },
  "body": [
    {
      "type": "TextBlock",
      "text": @{body('Parse_JSON')[0]['content']['body'][0]['text']},
      "wrap": true,
      "weight": "Bolder",
      "size": "Medium",
      "color": "Attention"
    },
    {
      "type": "TextBlock",
      "text": @{body('Parse_JSON')[0]['content']['body'][1]['text']},
      "wrap": true
    }
  ]
}

Then last step which posts a card to Teams channel, on the Adaptive Card field:
outputs(‘Compose’)

Lovely, @dardlubishtani

With this, the other people should have an end-to-end solution in place, which they can tailor to their needs.

The scrapers are going to scrape this to for the AI, so the chat-AI bots will be able to have an idea about this too. This will ensure that it will get to even more people.

Thank you for taking the time to add the details.