Reputation: 487
According to Slack's documentation is only possible to send one file per time via API. The method is this: https://api.slack.com/methods/files.upload.
Using Slack's desktop and web applications we can send multiple files at once, which is useful because the files are grouped, helping in the visualization when we have more than one image with the same context. See the example below:
Does anyone know if it's possible, via API, to send multiple files at once or somehow achieve the same results as the image above?
Thanks in advance!
Upvotes: 22
Views: 10310
Reputation: 11
Here is how I did the same thing using Go via the slack-go/slack library:
func uploadImagesToSlack(images []string, token string) ([]string, error) {
api := slack.New(token)
permalinkList := make([]string, 0, len(images))
for i, base64Image := range images {
imageData, err := base64.StdEncoding.DecodeString(base64Image)
if err != nil {
fmt.Printf("Error decoding image %d: %v\n", i, err)
continue
}
params := slack.FileUploadParameters{
Filename: fmt.Sprintf("image_%d.png", i+1),
Filetype: "auto",
Title: fmt.Sprintf("Image %d", i+1),
Content: string(imageData),
}
fileInfo, err := api.UploadFile(params)
if err != nil {
fmt.Printf("Error uploading file for image %d: %v\n", i+1, err)
continue
}
permalinkList = append(permalinkList, fileInfo.Permalink)
}
return permalinkList, nil
}
func postGalleryToSlack(permalinkList []string, channel, token string) error {
api := slack.New(token)
messageText := ""
for _, permalink := range permalinkList {
textSingleLink := fmt.Sprintf("<%s | >", permalink)
messageText = messageText + textSingleLink
}
channelID, timestamp, err := api.PostMessage(
channel,
slack.MsgOptionText(messageText, false),
)
if err != nil {
return err
}
fmt.Printf("Message successfully sent to channel %s at %s\n", channelID, timestamp)
return nil
}
The images were retrieved in a previous function and then encoded into base64 strings using base64.StdEncoding.EncodeToString()
, then this function is called which loops over the strings, decodes them, uploads to slack without posting, grabs the permalinks from the api.UploadFile() method, then posts them all in a single message which gives us the gallery format.
Upvotes: 0
Reputation: 31
it is possible with files_upload_v2
import slack_sdk
client = slack_sdk.WebClient(token=SLACK_TOKEN)
file_uploads = []
for file in list_of_files:
file_uploads.append({
'file' : file['path'],
'filename' : file['name'],
'title' : file['title']
})
new_file = client.files_upload_v2(
file_uploads=file_uploads,
channel=message['channel'],
initial_comment=text_message
)
Upvotes: 3
Reputation: 190
Here is an implementation of the procedure recommended in the other answer in python
def post_message_with_files(message, file_list, channel):
import slack_sdk
SLACK_TOKEN = "slackTokenHere"
client = slack_sdk.WebClient(token=SLACK_TOKEN)
for file in file_list:
upload = client.files_upload(file=file, filename=file)
message = message + "<" + upload["file"]["permalink"] + "| >"
out_p = client.chat_postMessage(channel=channel, text=message)
post_message_with_files(
message="Here is my message",
file_list=["1.jpg", "1-Copy1.jpg"],
channel="myFavoriteChannel",
)
Upvotes: 8
Reputation: 808
Python solution using new recommended client.files_upload_v2
(tested on slack-sdk-3.19.5 on 2022-12-21):
import slack_sdk
def slack_msg_with_files(message, file_uploads_data, channel):
client = slack_sdk.WebClient(token='your_slack_bot_token_here')
upload = client.files_upload_v2(
file_uploads=file_uploads_data,
channel=channel,
initial_comment=message,
)
print("Result of Slack send:\n%s" % upload)
file_uploads = [
{
"file": path_to_file1,
"title": "My File 1",
},
{
"file": path_to_file2,
"title": "My File 2",
},
]
slack_msg_with_files(
message='Text to add to a slack message along with the files',
file_uploads_data=file_uploads,
channel=SLACK_CHANNEL_ID # can be found in Channel settings in Slack. For some reason the channel names don't work with `files_upload_v2` on slack-sdk-3.19.5
)
(some additional error handling would not hurt)
Upvotes: 8
Reputation: 39
Simply use Slack Blocks: Block Kit Builder. Great feature for the message customizations.
Upvotes: -1
Reputation: 51
For Python you can use:
permalink_list = []
file_list=['file1.csv', 'file2.csv', 'file3.csv']
for file in file_list:
response = client.files_upload(file=file)
permalink = response['file']['permalink']
permalink_list.append(permalink)
text = ""
for permalink in permalink_list:
text_single_link = "<{}| >".format(permalink)
text = text + text_single_link
response = client.chat_postMessage(channel=channelid, text=text)
Here you can play around with the link logic - Slack Block Kit Builder
Upvotes: 1
Reputation: 13696
import pkg from '@slack/bolt';
const { App } = pkg;
import axios from 'axios'
// In Bolt, you can get channel ID in the callback from the `body` argument
const channelID = 'C000000'
// Sample Data - URLs of images to post in a gallery view
const imageURLs = ['https://source.unsplash.com/random', 'https://source.unsplash.com/random']
const uploadFile = async (fileURL) {
const image = await axios.get(fileURL, { responseType: 'arraybuffer' });
return await app.client.files.upload({
file: image.data
// Do not use "channels" here for image gallery view to work
})
}
const permalinks = await Promise.all(imageURLs.map(async (imageURL) => {
return (await uploadImage(imageURL)).file.permalink
}))
const images = permalinks.map((permalink) => `<${permalink}| >`).join('')
const message = `Check out the images below: ${images}`
// Post message with images in a "gallery" view
// In Bolt, this is the same as doing `await say({`
// If you use say(, you don't need a channel param.
await app.client.chat.postMessage({
text: message,
channel: channelID,
// Do not use blocks here for image gallery view to work
})
The above example includes some added functionality - download images from a list of image URLs and then upload those images to Slack. Note that this is untested, I trimmed down the fully functioning code I'm using.
Slack's image.upload
API docs will mention that the file format needs to be in multipart/form-data
. Don't worry about that part, Bolt (via Slack's Node API), will handle that conversion automatically (and may not even work if you feed it FormData). It accepts file data as arraybuffer
(used here), stream
, and possibly other formats too.
If you're uploading local files, look at passing an fs
readstream to the Slack upload function.
Upvotes: 1
Reputation: 753
I've faced with the same problem. But I've tried to compose one message with several pdf files.
How I solved this task
channel
parameter(this prevents publishing) and collect permalinks from response. Please, check file object ref. https://api.slack.com/types/file. Via "files.upload" method you can upload only one file. So, you will need to invoke this method as many times as you have files to upload.<{permalink1_from_first_step}| ><{permalink2_from_first_step}| >
- Slack parse links and automatically reformat messageUpvotes: 17