Sending messages to Mattermost or Slack Webhooks using Python 3

descriptionStandard

In this article I will demonstrate another method for posting messages to a Mattermost/Slack instance but this time from Python 3 by utilising an incoming webhook.

I previously covered how to make web requests and post messages from PowerShell.

Below is a custom class we will be utilising to send messages to Mattermost using Python 3.

class Matterhook:
    """
    Simple class to post messages to incoming webhooks on Mattermost/Slack.
    """

    # Default header to include in web request.
    header = {'content-type': 'application/json'}
    status_code = 0

    def post_message(self, url, message_payload, headers=None):
        """
        POST a message to an incoming webhook url and optionally customise the request header.
        :param url: A Mattermost or Slack webhook
        :type url: str
        :param message_payload: Message contents.
        :type message_payload: dict
        :param headers: Define custom headers for the request; defaults to `'content-type': 'application/json'`
        :type headers: dict
        :return: Response status code on success.
        :rtype: int
        """

        # This section performs some simple checks to determine if the arguments;
        # bool is used to indicate exiting the function and allows for printing multiple error message if appropriate.
        error = False

        if message_payload in ('', None):
            print('Empty payload provided.')
            error = True

        if not isinstance(message_payload, dict):
            print('Payload is expected as type: dictionary.')
            error = True

        if url in ('', None):
            print('Invalid or empty url.')
            error = True

        if error:
            return

        # Merge any included headers (will override existing) if a dictionary.
        if isinstance(headers, dict):
            self.header.update(headers)

        # Try to post the message to the supplied url.
        try:
            response = requests.post(url, data=json.dumps(message_payload), headers=self.header)
            # Enabling raising errors via status codes if available.
            response.raise_for_status()
            # Store status
            self.status_code = response.status_code
            return response
        except requests.exceptions.HTTPError as err:
            return print("Unexpected resulting status code: ", err)

In the example above the function post_message has 4 arguments, lets review them below:

ArgumentDescription
self
(internal)
Is used internally within the class to access class methods attributes.
webhook
(required)
A url, example: https://server-url.com/hooks/xxxxxxxxxxxxxxxxx
The value should be that of the incoming webhook you have generated on your server.
message (required)A message, example: Test message sent from PowerShell
username
(optional)
A name, example: Anomandaris
Function post_message from class Matterhook argument explanation.

This function can be used in a few ways; below are some examples on how to call the function from Python 3 and pass in additional data.

Send a message to a webhook with a custom username:

# Init class to post message
notify = Matterhook()

payload = {
    'text': 'Has anyone seen Soleil?'
}

notify.post_message('https://oddity.oddineers.co.uk/hooks/1234567890qwertyuiop', payload)

Send a message to a webhook; but override the default username:

notify.post_message('https://oddity.oddineers.co.uk/hooks/1234567890qwertyuiop', payload, 'Poliel')

Using matterping.py

The Python 3 script linked above also includes an example which when called directly from the CLI accepts several arguments; see the table below:

Short argsLong argsDescription
-w–webhookA url, example: https://server-url.com/hooks/xxxxxxxxxxxxxxxxx
The value should be that of the incoming webhook you have generated on your server.
-m–message A message, example: Test message sent from PowerShell
-u–usernameA name, example: Anomandaris
Script matterping.py argument explanation.

In the script matterping.py if you run it directly it will execute the code contained within the if __name__ == '__main__': block as shown below. You can use this and adopt it to build and post your own payloads.

if __name__ == '__main__':
    import argparse

    parser = argparse.ArgumentParser()
    # Adds optional arguments to the script to set the webhook url, message and username
    # All arguments are optional as we will handle required args in our basic class.
    parser.add_argument('-w', '--webhook', dest='webhook', help='Incoming Webhook address.', type=str)
    parser.add_argument('-m', '--message', dest='message', help='Body of message.', type=str)
    parser.add_argument('-u', '--username', dest='username', help='Username to post as.', type=str)
    args = parser.parse_args()

    payload = {
        'text': args.message
    }

    # If username is provided
    if args.username:
        payload['username'] = args.username

    # Init class to post message
    notify = Matterhook()
    notify.post_message(args.webhook, payload)

    # Print help if response was not successful; not 20x
    if notify.status_code not in [200, 201]:
        parser.print_help()

Example script usage:

# Short args
matterping.py -w https://oddity.oddineers.co.uk/hooks/1234asde4321edsa1234 -m "Test message"

# Long args
matterping.py --webhook https://oddity.oddineers.co.uk/hooks/1234asde4321edsa1234 --message "Test message"

# Short args + username
matterping.py -w https://oddity.oddineers.co.uk/hooks/1234asde4321edsa1234 -m "Test message" -u "Poliel"

# These hook urls are not real.

Additional information

Now depending upon which service you are using; Mattermost or Slack you may be required to adjust the contents of the payload sent to the server. To do this find the section below and adjusting the contents to suit your needs.

    payload = {
        'text': args.message
    }

    # If username is provided
    if args.username:
        payload['username'] = args.username