[BTY] Day 14: How to send notification from your Python app to Slack?

nguyendhn

Dang Hoang Nhu Nguyen

Posted on February 21, 2022

[BTY] Day 14: How to send notification from your Python app to Slack?

This post was for 18.02.2022

A lot of time, you want to be noticed when something happens to your application on the server, so you can take action as soon as possible.

Sending Slack messages to a channel in case of exceptions (with phone notifications, emails included in settings) is one of the simplest ways I found to deal with the mentioned issue.

Disclaimer: This is a legacy custom integration - an outdated way for teams to integrate with Slack. You may visit the Slack documentation for update and the modern way to do so.

1. Create new Slack workspace

create new Slack

2. Setting up

  • Create new channel ⇒ Right click and select Open channel details

create new slack channel

  • Integrations > Add an App

Add an app

  • Search and select Incoming Webhooks

Add incoming webhooks

  • Add Incoming WebHooks to the target channel (e.g #test-notification)

add app to target channel

Setup Instructions (from the documentation)

We'll guide you through the steps necessary to configure an Incoming Webhook so you can start sending data to Slack.

Webhook URL

https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxx

Sending Messages

You have two options for sending data to the Webhook URL above:

  • Send a JSON string as the payload parameter in a POST request
  • Send a JSON string as the body of a POST request

For a simple message, your JSON payload could contain a text property at minimum. This is the text that will be posted to the channel.

A simple example:

    payload={"text": "This is a line of text in a channel.\nAnd this is another line of text."}
Enter fullscreen mode Exit fullscreen mode

This will be displayed in the channel as:

https://a.slack-edge.com/80588/img/integrations/incoming_webhook_example1.png

Adding links

To create a link in your text, enclose the URL in <> angle brackets. For example: payload="text": "" will post a clickable link to https://slack.com. To display hyperlinked text instead of the actual URL, use the pipe character, as shown in this example:

    payload={"text": "A very important thing has occurred! <https://alert-system.com/alerts/1234|Click here> for details!"}
Enter fullscreen mode Exit fullscreen mode

This will be displayed in the channel as:

https://a.slack-edge.com/80588/img/integrations/incoming_webhook_example2.png

Customized Appearance

You can customize the name and icon of your Incoming Webhook in the Integration Settings section below.However, you can override the displayed name by sending "username": "new-bot-name" in your JSON payload. You can also override the bot icon either with "icon_url": "https://slack.com/img/icons/app-57.png" or "icon_emoji": ":ghost:".

Channel Override

Incoming webhooks have a default channel, but it can be overridden in your JSON payload. A public channel can be specified with "channel": "#other-channel", and a Direct Message with "channel": "@username".

Example

Putting this all together, here is a sample curl request for posting to a channel.

    curl -X POST --data-urlencode "payload={\"channel\": \"#test-notification\", \"username\": \"webhookbot\", \"text\": \"This is posted to #test-notification and comes from a bot named webhookbot.\", \"icon_emoji\": \":ghost:\"}" https://hooks.slack.com/services/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
Enter fullscreen mode Exit fullscreen mode

This will be displayed in the channel as:

https://a.slack-edge.com/80588/img/integrations/incoming_webhook_example3.png

Python Code

    import requests
    from loguru import logger

    class SlackWebhookBot:
        def __init__(self, webhook_url: str,
                     channel_name: str = "test-notification",
                     bot_name: str = "guardian",
                     bot_emoji: str = ":guardsman:",
                     timeout: int = 15):
            """Class to send messages to a provided Slack webhook URL.

            You can read more about Slack's Incoming Webhooks here:
                https://api.slack.com/messaging/webhooks

            Args:
                webhook_url: The webhook URL to send a message to.  Typically
                    formatted like "https://hooks.slack.com/services/...".

            Kwargs:
                timeout: Number of seconds before the request will timeout.
                    This is used to prevent a hang and is set to a default
                    value of 15 seconds.
            """
            self.webhook_url = webhook_url
            self.channel_name = channel_name
            self.bot_name = bot_name
            self.bot_emoji = bot_emoji
            self.timeout = timeout
            self.headers = {
                'Content-Type': 'application/json',
            }

        def send_notification(self, message: str) -> bool:
            """Sends a message to the webhook URL.

            Per the Slack Incoming Webhook example.  The body of the request
            (for plain text) should be formatted as follows:
                `{"text": "Hello, World!"}`

            Args:
                message: Plain text string to send to Slack.

            Returns:
                A boolean representing if the request was successful.
            """
            success = False
            payload = {
                'channel': self.channel_name,
                'username': self.bot_name,
                'icon_emoji': self.bot_emoji,
                'text': message,
            }
            try:
                requests.post(
                    self.webhook_url,
                    headers=self.headers,
                    json=payload,
                    timeout=self.timeout
                )
            except requests.Timeout:
                logger.error('Timeout occurred when trying to send message to Slack.')
            except requests.RequestException as e:
                logger.error(f'Error occurred when communicating with Slack: {e}.')
            else:
                success = True
                logger.info('Successfully sent message to Slack.')

            return success

    if __name__ == '__main__':
        SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/xxxxxxxxx"
        slack = SlackWebhookBot(SLACK_WEBHOOK_URL)
        slack_test_message = '[TESTING] Sending this warning message when we have any problems.'
        logger.info(slack.send_notification(message=slack_test_message))
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
nguyendhn
Dang Hoang Nhu Nguyen

Posted on February 21, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

[BTY] Day 5: ctime() does not refer to creation time
betterthanyesterday [BTY] Day 5: ctime() does not refer to creation time

February 9, 2022

[BTY] Day 2: REST Resource Naming Guide
betterthanyesterday [BTY] Day 2: REST Resource Naming Guide

February 6, 2022

[BTY] Day 12: Auto resurrecting tmux sessions
betterthanyesterday [BTY] Day 12: Auto resurrecting tmux sessions

January 9, 2022