The free Slack collaboration environment combined with the Slack Python API is a great way to automate simple tasks with simple Chat-Bots, automated scripts and background processes that can be written in Python and triggered from Slack on demand.
This blog article leaves the details of what you do with Slack API and just goes through the mechanics of:
Part 1: Posting messages to Slack from a Python client (simple one-way broadcasts to a Slack channel)
Part 2: Two-way interactive communication between a Slack channel and a Python process (this could either be a Python process listening for commands or an interactive chat-bot)
Part 1 – Authentication to Slack and One-Way Posts to Slack
Part 1 will get us authorised to send messages into Slack channels.
1.1 Create a New Application
Go to the https://api.slack.com/apps URL to create a new application.
Give the App a suitable name – pythonbot
for instance, and select the Workspace this should be registered with (the app is registered with the whole Slack Workspace, not just a particular channel, so you need permissions to do this).
1.2 Review and Set Basic App Information
Scroll down the Basic Information page for the new App. Note the various App Credentials provided for authenticating to Slack:
However for the latest Python Slack API client, we don’t need any of the tokens listed on this page.
Scroll down to the bottom of the form, give the App a description and set the background colour in the Display Information section and then select Save Changes.
1.3 Set App Permissions for Workspace and Get OAuth Token
Now we need to get an OAuth Authentication Token for the new App. From the https://api.slack.com/apps page, click on the App you have just created go to the OAuth and Permissions page (select this from the Left Hand Menu bar as shown in the screenshot below)
- Add Permission Scopes to allow actions for this API – EG
chat:write:bot, channels:read
- Do this by selecting from the drop-down list of options and then saving the changes.
- To select all of the above permissions you have to select the permission scopes in two separate steps, saving the changes after each scope operation.
- Go back to the top of the web-page and select Install App to Workspace.
1.4 Authorize the App
When the Install App to Workspace button is selected, it should trigger a re-direct to a page that requests authorisation of the new App to be added to the Workspace. Select Authorize to move to the page providing the OAuth token.
1.5. Obtain the OAuth Token
After selecting Authorize, the “OAuth & Permissions” page reloads with a generated OAuth Token:
Click copy to copy the token string and paste this into a text-pad somewhere for future use.
1.6 Test Sending Messages to Slack from the Python Slack API
First, install the Slack Client for Python:
pip install slackclient
The Slack Client uses web-sockets, so as long as HTTP is enabled through your firewall, this should work.
Use this simple script to check things are working and we can send messages to Slack:
from slackclient import SlackClient # Token is stored in code for this test ##!! Don't check this in to GitHub!! ## slack_token = '_your_token_here_' sc = SlackClient(slack_token) sc.api_call( "chat.postMessage", channel="", text="Hello from Python! :tada:", reply_broadcast=True )
Use the OAuth Token obtained in section 1.5 that was provided when the new App was registered.
For a destination channel to send messages to, you can specify any public channel in the Workspace that this App is registered in. (Note – include the preceding “#” when specifying the channel)
If everything is working, the message “Hello from Python!” should appear in the specified channel.
Part 2 – Two Way Communication between Slack and Python Processes
Two-way communication (including receiving input from Slack into a Python process) is more complicated.
However, things are much easier than they were in the past. Previously you had to set up a web-hook process to listen to the Slack Channel and link it to our Python program. Now the Slack Client handles this for us via the Bot Users configuration option.
2.1 Create a Bot User
Go to the main Slack Apps configuration menu at https://api.slack.com/apps , select the name of the App created in the previous steps (EG pythonbot
in these examples) and then select the Bot Users configuration menu:
Select Add a Bot User. This then provides the option to provide a different Display Name and Default Username than the default (which is just the name of the app).
Either leave the default values as they are or provide alternatives and then click Add Bot User to save these changes and add the bot user.
After Adding the Bot User, make sure you Save Changes.
2.2 Authorise the Bot User
As soon as you save the changes to add the new Bot User, the Slack admin interface should re-direct you to a web-form prompting you to authorise the the Bot User and add it to the Workspace:
After selecting Authorize, you can then pick up the new OAuth token to authorise this Bot-User with.
2.4 Obtain the Bot User OAuth Token
Obtain the Bot User Oauth Token from the Oauth & Permissions menu. This is a different token to the one identified previously in Part 1 that allowed messages to posted to public channels.
This token is shorter than the other tokens – at the time of writing in the format:
xoxb-999999999999-999999999999-*************************
Copy the token and paste it into a text-pad session for future reference.
(do not click on Reinstall App)
2.5 Invite the Bot-User to a Channel
Before the Bot can communicate in a channel, it needs to be invited to that channel. In the example below, the pythonbot
Bot User is invited to the channel #test
.
2.6 Interactive 2-way chat with a Bot – Python echo-bot.
To demonstrate the concept of a Bot that listens to input on a Slack channel and processes what is being said and responds with a message based on the input, the following “echo-bot” script demonstrates the basic functionality. This provides all the bare-bones components for developing a more functionally rich chat-bot utility in Python and connecting it to Slack.
First, instead of coding the OAuth tokens into our script (which is very insecure) we should either
- Export the token value in the shell environment before running our echo-bot utility
Or
- Create a shell script to conveniently set an environment variable with token value each time we start our echo bot. Make sure the script is not world-readable.
Either way, the syntax in Linux is:
export SLACK_BOT_TOKEN=xoxb-999999999999-999999999999-*************************
(where the actual token values have been obscured in this example). Simply place the above single line in a shell script such as env.sh
and execute as follows
. ./env.sh
to set the SLACK_BOT_TOKEN
environment variable so that it can be picked up by the Python script (note the extra “dot”). We reference the shell environment variable in Python using os.environ.get
The following script sets up a send-and-receive channel between a Slack channel and a Python client and implements a simple “echo-bot” utility. This example is copied and modified from here: https://www.fullstackpython.com/blog/build-first-slack-bot-python.html
import os import re import time from slackclient import SlackClient # Instantiate an authenticated Slack client sc = SlackClient(os.environ.get('SLACK_BOT_TOKEN')) # Bot ID in Slack: ssigned when the bot starts up bot_id = None # Constants READ_DELAY = 0.5 #delay between reading messages MENTION_REGEX = "^(.*)" # Get a dictionary of users in this Workspace def init_users_dict(): users={} users_extract = sc.api_call("users.list") for item in users_extract['members']: if not item['is_bot']: user_data_tuple = ((item['name'] , item['profile']['display_name'] , item['real_name'])) users.update( {item['id'] : user_data_tuple } ) return users # Map a users ID to either display name or real name def map_user(ident, users): if users[ident][1]: return users[ident][1] else: return users[ident][2] # Parse a slack event and extract the message # and information about channel, fromuser ID, touser ID def get_msg(slack_events): for event in slack_events: if event["type"] == "message" and not "subtype" in event: touser = None message_text = event["text"] channel = event["channel"] fromuser = event["user"] matches = re.search(MENTION_REGEX, message_text) if matches: touser = matches.group(1) message = matches.group(2) else: message = message_text return message, channel, fromuser, touser else: return None, None, None, None # Send a message on a specific channel ID def send_msg(message, channel): sc.api_call( "chat.postMessage", channel=channel, text=message, icon_emoji=':robot_face:' ) ### MAIN #### if __name__ == "__main__": if sc.rtm_connect(with_team_state=True): print("Echo-Bot connected and running") users = init_users_dict() # Get Bot ID by calling API method `auth.test` bot_id = sc.api_call("auth.test")["user_id"] while True: msg, chnl, fromuser, touser = get_msg(sc.rtm_read()) if msg: if touser == bot_id: ## Incoming Message logic here ## sender_name = map_user(fromuser,users) msg_back = "Hello " + sender_name + ":" + msg send_msg(msg_back, chnl) time.sleep(READ_DELAY) else: print("Connection failed")
When this script is run, it connects to Slack and loops for ever listening to messages for “@pythonbot” and parsing messages and replying to them.
As it stands in this example it just echoes a response back, but this demonstrates the basic framework needed for getting a python script to operate interactively with a Slack channel.