Last week I was working on a Databricks script that needed to produce a Slack message as its final outcome. I lifted some code that used a Slack client that was PIP-installed. Unfortunately, I could not install that package on my cluster. Fortunately, the Slack API is so simple, that you don't really need a package to post a simple message to a channel. In this blog, I'll show you the simplest way of producing awesome messages in Slack. No packages, just Python.
This code is not only applicable to Databricks. This will work in any Python script, application or notebook. Enojy!
- Intro
- Setup
- Posting to a channel
- How about blocks?
- How about files?
- Debugging
- Scripts: BASH me?
- Conclusion
- Improvements
- Comments
Setup
I like to manage my settings in a central place, so let's create some variables to store the slack token and channel (note: it should start with a #
).
slack_token = 'xoxb-my-bot-token'
slack_channel = '#my-channel'
slack_icon_emoji = ':see_no_evil:'
slack_user_name = 'Double Images Monitor'
I use the same bot for all my messages. To let my users know which application is sending the message, I use a per application icon and user name.
I usually use a single cell for my imports:
import requests
import json
Posting to a channel
The Slack API provides a nice chat.postMessage endpoint that we can use. We'll post a dictionary to the endpoint and a message will appear in our Slack channel:
def post_message_to_slack(text, blocks = None):
return requests.post('https://slack.com/api/chat.postMessage', {
'token': slack_token,
'channel': slack_channel,
'text': text,
'icon_emoji': slack_icon_emoji,
'username': slack_user_name,
'blocks': json.dumps(blocks) if blocks else None
}).json()
The only thing we need to do is call the function with a text, for example:
slack_info = 'There are *{}* double images detected for *{}* products. Please check the <https://{}.s3-eu-west-1.amazonaws.com/{}|Double Images Monitor>.'.format(
double_images_count, products_count, bucket_name, file_name)
post_message_to_slack(slack_info)
It will look like this:

Help, my icons are not showing?!
Slack did some changes, so your bot / integration needs to have the chat:write.customize permission. If it does not have that permission the username and icon of the bot are shown.
How about blocks?
I. Love. The. Block. Kit. It allows us to build complex messages, like this:
You can design block kit messages in the Block Kit Builder. I use Python objects to generate the blocks. A block-message can be sent by like this:
blocks = [{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":check: The script has run successfully on the dev."
}
}]
post_message_to_slack(
"Text shown in popup.",
blocks);
How about files?
We can send files through the file.upload API. Unfortunately, it does not support the username
and icon_url
properties.
def post_file_to_slack(
text, file_name, file_bytes, file_type=None, title=None
):
return requests.post(
'https://slack.com/api/files.upload',
{
'token': slack_token,
'filename': file_name,
'channels': slack_channel,
'filetype': file_type,
'initial_comment': text,
'title': title
},
files = { 'file': file_bytes }).json()
It makes sending text files super easy:
post_file_to_slack(
'Check out my text file!',
'Hello.txt',
'Hello World!')
Which is displayed like this:

Also, sending binary data is easy. This code downloads the image URL and passes the bytes on to the function:
import urllib.request
image = "https://images.unsplash.com/photo-1495954484750-af469f2f9be5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
response = urllib.request.urlopen(image)
data = response.read()
post_file_to_slack(
'Amazing day at the beach. Check out this photo.',
'DayAtTheBeach.jpg',
data)
Which looks like this:
Debugging
The Slack API works a little different from other APIs. When a request is invalid, it returns an HTTP 200 with a JSON error message. Because all of our methods return the JSON value, debugging is easy! Just print out the result:
print(post_blocks_to_slack("What is the matter with you!?", {}))
This will tell you all you need to know:
{'ok': False, 'error': 'invalid_blocks_format'}
Scripts: BASH me?
Some people use Python in their scripting. If you are writing a BASH script, you don't HAVE to use Python to send something to Slack. Just use the following BASH function to send a text via cURL to Slack:
#!/bin/bash
function post_message_to_slack() {
# Parameters:
# $1 is the slack channel, should start with a #
# $2 is the text message
local slack_token='xoxb-'
local slack_icon_url='https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTuGqps7ZafuzUsViFGIremEL2a3NR0KO0s0RTCMXmzmREJd5m4MA&s'
local slack_user_name='Double Images Monitor'
local slack_channel="$1"
local text="$2"
curl --request POST \
--data-urlencode "token=$slack_token" \
--data-urlencode "channel=$slack_channel" \
--data-urlencode "icon_url=$slack_icon_url" \
--data-urlencode "username=$slack_user_name" \
--data-urlencode "text=$text" \
'https://slack.com/api/chat.postMessage' \
-w "\n"
}
You can now use it like this:
post_message_to_slack "#chatops-tests" "To be, or not to be! 🤔"
Conclusion
Slack API. Is. Super. Simple. So... you don't really need a package to post a message to a Slack channel. Adding messages to your Python scripts and applications will give your end-users a richer experience. That's why I love ChatOps.
After thought: you might want to consider to just add a simple web hook.
Improvements
- 2021-06-07: Added the Help, my icons are not showing?! section. Also I swapped the icon URL out for a Slack emoji, which has way better security.
- 2020-03-14: Formatting / highlighting of the code.
- 2020-07-03: Added a pure BASH/cURL example.
- 2019-11-07: Merged sending of blocks and sending of text messages.
- 2019-11-05: Added
.json()
returns for all methods to support better debugging. Added debugging section. Added support for blocks. - 2019-10-31: Added support for files.
- 2022-09-07: Added the webhook link.
Would there be a way to use the user token? I couldn’t find a way to get my user token.
I’m not sure, I always use bot tokens in my applications. The docs (https://api.slack.com/methods/chat.postMessage) say that a user token should be able to do the same operation.
how do I notify someone inside the message? Tried @username and <@username>, but neither worked =/
What worked for me was:
slack_info = ‘Hello world! <@kbakker>‘
post_message_to_slack(slack_info)
My usename (@kbakker) is not the same as my display name (@kz). It prints the following in my Slack: https://uploads.disquscdn.com/images/c4b338c2edb63673a2270a6ab3f7a1aaf6a69a4895e750f4cfa8bd8a3482bc78.png
How do i send message to a user instead of a channel ?
OP, I would like to say a big thank you for sharing these codes :)
Hi! How would we possibly send @Channel notifications in this? I tried the recommendation you put lower @keescbakker:disqus , but it only worked for individual users.
Additionally, can we use this to call another slash command? Say I want to use a slash command called /exports that checks for how many people updated their files. Is there a mechanism that allows that to be passed, and read by the client in a way that the slash command executes as if i had typed it in?
Thank you for this article and information!!!
As far as I know “@channel” and “@here” can only be invoked by users that are in the chat. The same goes for slash commands.