This article details how to use the
slack-sdk
PyPI package to upload files
to Slack with some code samples. By the end of article, you will know how to:
files.upload
and files.list
methods.Without further ado, let's start by creating a Slack app.
Use the following button to create a new Slack app.
Creating your app using this method will include all the required settings for this tutorial and you won't be bogged down with too much of the nitty-gritty details -- all you'll need to do is decide on which workspace this app will live. Just in case you're curious about the inner workings of how this button works, check out more information on App Manifests.
_metadata:
major_version: 1
minor_version: 1
display_information:
name: File Writer App
features:
bot_user:
display_name: File Writer Bot
oauth_config:
scopes:
bot:
# Used to send messages to a channel
- chat:write
# This scope is not required if your app will just upload files. We've included it in order to use the `files.info` `files.list` methods.
- files:read
# Used to upload files to Slack
- files:write
Once you've created your app, you'll see an Install to Workspace button. Click it and install your app onto your workspace.
Next, click Allow in order to authorize this app on your workspace.
Now that you've finished installing the app, navigate to the Install App section under Settings. Here you'll find your Bot User OAuth Token
.
Set this token value as an environment variable called SLACK_BOT_TOKEN
by using the following command within a command prompt:
export SLACK_BOT_TOKEN=xoxb-11111111111-2222222222-dssdfswsddjfh34sfdsfs
With this, all your Slack app configuration is done. Let's start coding.
First, make sure that you're using Python version 3.6 or above.
While the current standard is for the python3
and pip3
commands to use Python 3.6 or above, it's best to make sure that your runtime is always using the latest version of Python. pyenv is a handy tool that can do this for you.
We'll create a brand new virtual environment and install the required library dependencies using the following commands.
echo 'slack-sdk>=3.12,<4' > requirements.txt
python3 -m venv .venv
source .venv/bin/activate
pip install -U pip
pip install -r requirements.txt
While it's possible to enter the following into the Python shell, we've gathered some code samples and wrote it in script form.
For each of the code samples, make sure to add in the following to the top of your Python file if you're going to run it as a script. We've left this out for clarity within the article but the examples won't run without it.
import logging, os
# Sets the debug level.
# If you're using this in production, you can change this back to INFO and add extra log entries as needed.
logging.basicConfig(level=logging.DEBUG)
# Initialize the Web API client
# This expects that you've already set your SLACK_BOT_TOKEN as an environment variable
# Try to resist the urge to put your token directly in your code, as it is best practice not to.
from slack_sdk import WebClient
client = WebClient(os.environ["SLACK_BOT_TOKEN"])
Let's make sure that our token is correctly configured.
# Tests to see if the token is valid
auth_test = client.auth_test()
bot_user_id = auth_test["user_id"]
print(f"App's bot user: {bot_user_id}")
Once you run this code, you'll see something similar to the following within the logs:
>>> auth_test = client.auth_test()
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/auth.test, query_params: {}, body_params: {}, files: {}, json_body: None, headers: {}
DEBUG:slack_sdk.web.base_client:Received the following response - status: 200, headers: {}, body: {"ok":true,"url":"https:\/\/example.slack.com\/","team":"Acme Corp","user":"file_writer_bot","team_id":"T1234567890","user_id":"U02PY3HA48G","bot_id":"B02P8CPE143","is_enterprise_install":false}
>>> bot_user_id = auth_test["user_id"]
>>> print(f"App's bot user: {bot_user_id}")
App's bot user: U02PY3HA48G
Notice that the your bot user's user_id
can be found within these logs. Any files uploaded using a bot token will be associated with the bot user.
At this point, while no files have been uploaded yet, you can call the files.list
method to confirm this fact. We'll do this once again after we've uploaded some files to see what has changed.
>>> files = client.files_list(user=bot_user_id)
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/files.list, query_params: {}, body_params: {'user': 'U02PY3HA48G'}, files: {}, json_body: None, headers: {}
DEBUG:slack_sdk.web.base_client:Received the following response - status: 200, headers: {}, body: {"ok":true,"files":[],"paging":{"count":100,"total":0,"page":1,"pages":0}}
Let's try uploading a file using text supplied to the content
parameter. This will upload a text file with the specified content
.
new_file = client.files_upload(
title="My Test Text File",
filename="test.txt",
content="Hi there! This is a text file!",
)
Doing this within the Python shell will spit out the following:
>>> new_file = client.files_upload(
... title="My Test Text File",
... filename="test.txt",
... content="Hi there! This is a text file!",
... )
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/files.upload, query_params: {}, body_params: {'filename': 'test.txt', 'title': 'My Test Text File', 'content': 'Hi there! This is a text file!'}, files: {}, json_body: None, headers: {}
DEBUG:slack_sdk.web.base_client:Received the following response - status: 200, headers: {}, body: {"ok":true,"file":{"id":"F02P5J88137","created":1638414790,"timestamp":1638414790,"name":"test.txt","title":"My Test Text File","mimetype":"text\/plain","filetype":"text","pretty_type":"Plain Text","user":"U02PY3HA48G","editable":true,"size":30,"mode":"snippet","is_external":false,"external_type":"","is_public":false,"public_url_shared":false,"display_as_bot":false,"username":"","url_private":"https:\/\/files.slack.com\/files-pri\/T03E94MJU-F02P5J88137\/test.txt","url_private_download":"https:\/\/files.slack.com\/files-pri\/T03E94MJU-F02P5J88137\/download\/test.txt","permalink":"https:\/\/seratch.slack.com\/files\/U02PY3HA48G\/F02P5J88137\/test.txt","permalink_public":"https:\/\/slack-files.com\/T03E94MJU-F02P5J88137-e3fda671e9","edit_link":"https:\/\/seratch.slack.com\/files\/U02PY3HA48G\/F02P5J88137\/test.txt\/edit","preview":"Hi there! This is a text file!","preview_highlight":"<div class=\"CodeMirror cm-s-default CodeMirrorServer\" oncopy=\"if(event.clipboardData){event.clipboardData.setData('text\/plain',window.getSelection().toString().replace(\/\\u200b\/g,''));event.preventDefault();event.stopPropagation();}\">\n<div class=\"CodeMirror-code\">\n<div><pre>Hi there! This is a text file!<\/pre><\/div>\n<\/div>\n<\/div>\n","lines":1,"lines_more":0,"preview_is_truncated":false,"comments_count":0,"is_starred":false,"shares":{},"channels":[],"groups":[],"ims":[],"has_rich_preview":false}}
We can confirm that a file has been uploaded using the files.list
method mentioned earlier. Wait a moment before calling this method as there may be a bit of a lag before files are reflected within the results.
>>> files = client.files_list(user=bot_user_id)
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/files.list, query_params: {}, body_params: {'user': 'U02PY3HA48G'}, files: {}, json_body: None, headers: {}
DEBUG:slack_sdk.web.base_client:Received the following response - status: 200, headers: {}, body: {"ok":true,"files":[{"id":"F02P5J88137","created":1638414790,"timestamp":1638414790,"name":"test.txt","title":"My Test Text File","mimetype":"text\/plain","filetype":"text","pretty_type":"Plain Text","user":"U02PY3HA48G","editable":true,"size":30,"mode":"snippet","is_external":false,"external_type":"","is_public":false,"public_url_shared":false,"display_as_bot":false,"username":"","url_private":"https:\/\/files.slack.com\/files-pri\/T03E94MJU-F02P5J88137\/test.txt","url_private_download":"https:\/\/files.slack.com\/files-pri\/T03E94MJU-F02P5J88137\/download\/test.txt","permalink":"https:\/\/seratch.slack.com\/files\/U02PY3HA48G\/F02P5J88137\/test.txt","permalink_public":"https:\/\/slack-files.com\/T03E94MJU-F02P5J88137-e3fda671e9","edit_link":"https:\/\/seratch.slack.com\/files\/U02PY3HA48G\/F02P5J88137\/test.txt\/edit","preview":"Hi there! This is a text file!","preview_highlight":"<div class=\"CodeMirror cm-s-default CodeMirrorServer\" oncopy=\"if(event.clipboardData){event.clipboardData.setData('text\/plain',window.getSelection().toString().replace(\/\\u200b\/g,''));event.preventDefault();event.stopPropagation();}\">\n<div class=\"CodeMirror-code\">\n<div><pre>Hi there! This is a text file!<\/pre><\/div>\n<\/div>\n<\/div>\n","lines":1,"lines_more":0,"preview_is_truncated":false,"channels":[],"groups":[],"ims":[],"comments_count":0}],"paging":{"count":100,"total":1,"page":1,"pages":1}}
Now if we head back to Slack, you'll notice that nothing has happened. How curious...
At this point, we have indeed uploaded a file to Slack but only the bot user is able to view it.
Let's share this file with other users within our workspace. In order to do so, we'll use the chat.postMessage
method to post a message.
Let's use the #random
channel for this, but you're welcome to use any channel. Just like in the image below, mention the File Writer Bot and invite it to the #random
channel.
Next, use the following code to retrieve the file's permalink and post it within a channel.
file_url = new_file.get("file").get("permalink")
new_message = client.chat_postMessage(
channel="#random",
text=f"Here is the file: {file_url}",
)
By doing this, you'll be able to see the file within Slack.
While this exercise was very informative, having to do these two steps every time we upload a file is a bit cumbersome. Instead, we can specify the channels
parameter to the files.upload
method. This is the more common way of uploading a file from an app.
It's possible to use a single string, like the example below or multiple channel IDs in the form of an array of strings when specifying the channels
parameter. In this example, we've used the channel name #random
but it's best practice to use channel IDs as channel names can change without warning.
upload_and_then_share_file = client.files_upload(
channels="#random", # You can specify multiple channels here in the form of a string array
title="Test text data",
filename="test.txt",
content="Hi there! This is a text file!",
initial_comment="Here is the file:",
)
By running the above code, you'll share the same file without having to send a message with the file URL.
If you have an image file lying around, feel free to use that but for simplicity's sake, we'll continue using a text file here. You can create a local file by using the following command within a command prompt:
echo 'Hi there! This is a text file!' > test.txt
Next, within the same directory, execute the following code. We'll specify the file path as the file
parameter.
upload_text_file = client.files_upload(
channels="#random",
title="Test text data",
file="./test.txt",
initial_comment="Here is the file:",
)
And again, we'll see that the file has been uploaded to Slack and shared within the #random
channel.
The files.upload
method has several more parameters that we haven't talked about here. The method's documentation page has all the details on these parameters so take a look and play around.
Next, we'll cover how to delete a file through the API.
We've just uploaded 3 different files above (even though they may look the same). We can confirm that again using the files.list
method.
file_ids = []
# The Python SDK will automatically paginate for you within a for-loop.
for page in client.files_list(user=bot_user_id):
for file in page.get("files", []):
file_ids.append(file["id"])
print(file_ids)
>>> file_ids
['F02P5J88137', 'F02P8H5BN9G', 'F02P5K7T8SZ']
Let's remove these files from our Slack workspace.
for page in client.files_list(user=bot_user_id):
for file in page.get("files", []):
client.files_delete(file=file["id"])
Once we run this, the files
array should be empty pretty quick. On the other hand, the count for files found within the paging
object may take a moment to reflect the actual number of files.
You'll also notice within Slack that there are several This file was deleted.
messages being shown.
This article summarized how to use the Slack API to upload files and share them within a channel, using official Python SDK code snippets. The same principles apply to other languages as well, so if Python isn't your fancy, feel free to try out our other SDKs!
This article is loosely translated from the Japanese version by @seratch.