Send multiple files to Slack via API
Asked Answered
A

8

21

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:

enter image description here

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!

Alphonsealphonsine answered 27/1, 2020 at 21:37 Comment(0)
G
16

I've faced with the same problem. But I've tried to compose one message with several pdf files.

How I solved this task

  1. Upload files without setting 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.
  2. Compose message using Slack markdown <{permalink1_from_first_step}| ><{permalink2_from_first_step}| > - Slack parse links and automatically reformat message
Genni answered 13/8, 2020 at 8:23 Comment(7)
Interesting. I'll try that. Thanks!Alphonsealphonsine
This worked for me. I implemented it in python and have put that in a separate answer.Stoma
If folks have issues with this, I found that this will not work in a markdown message block using the Block kit - it only works for messages with markdown sent using the text param in the message payloadPalaeontography
Note that the space after the | is important, otherwise the full URL will show up in the message body as well as attaching the file.Pettit
I was following this strategy myself, but I have a surprising problem with it. If I omit the channels parameter, then the permalinks don't work. The permalink URLs, when followed, open the "Files" sidebar with a message that says "This file was not found.". If I include the channels parameter, the permalinks do work, but the uploads are published separately in the channel. Do you have any thoughts about this?Scanty
I posted a question about this here, but if you have any thoughts I'd be glad to hear them.Scanty
@MarkDominus it should work without the channels param, following this strategy. Just make sure if you're using web API that you do what @ahollenback said and NOT use blocks. Just a text param.Jemima
S
7

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",
)
Stoma answered 23/6, 2021 at 20:30 Comment(0)
N
7

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)

Nola answered 21/12, 2022 at 17:37 Comment(0)
S
2

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
                )
Susannsusanna answered 10/8, 2023 at 2:34 Comment(0)
J
1

A Node.JS (es6) example using Slack's Bolt framework

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.

Jemima answered 22/7, 2022 at 4:18 Comment(6)
Hi @chris if it's not too late, I have a question can I pass an arrayBuffer to the Slack API in its attachments? In my case my flow would be to send an arraybuffer from the front end for the API to receive and pass it to the slack API. i am using nodejsHammurabi
@Hammurabi yeah I don't think Slack is too picky, if it's an arrayBuffer, than the upload function should accept it. If you're sending it to your backend should still work, just be wary of the gotchas of file attachments if you're doing it with form-data in a form submission. api.slack.com/methods/files.upload/codeJemima
Hello! Thanks for answering, I tried to upload the file through a buffer, and although it works and even gives me a preview of the pdf I sent, I can't download it and it doesn't have the file name either. I did it with a formdata and in the backend I used the multer library to read the buffer but I don't know why I can't download itHammurabi
@Hammurabi interesting. I've only done it with images, so I'm not sure if there are other things to think about with PDFs. Try looking into whether the uploaded files are "public", with image preview iirc it uploads the files to Slack (not connected to any channel), and then makes them "public", and then public links can be used to access the images in any channel. But, Slack does this on their side behind the scenes or something? I vaguely recall reading about slack having that hack for image gallery view. Also, with the upload API you can manually set the filename, so you could try that as well.Jemima
Thanks for guiding me, after your comment I looked in the documentation how Slack handled the files, so I noticed that I wasn't really sending it an extension and a name, that was my problem. I'm sorry for the inconvenience, I'm new to managing the api, there are still things I have to learn, but thanks to you I solved it. Can I ask one last question? Do you know if through the api I can attach multiple files always using buffers?Hammurabi
@Hammurabi nice! I didn't know leaving out the filename would be an issue. Sorry, I'm not super familiar with the API, I've just used the single file upload method for images. If you're specifically referring to multiple files side-by-side in a single message, the only way is the weird message formatting approach you're using now. Slack doesn't have any other way to do this in their API. You can still put each file in separate messages (ie using the Block Kit Builder) for however many files you have, it will just look less pretty without the side-by-side view.Jemima
A
1

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

Aude answered 28/7, 2022 at 18:29 Comment(0)
D
0

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.

Denitrify answered 19/3 at 16:37 Comment(0)
O
-1

Simply use Slack Blocks: Block Kit Builder. Great feature for the message customizations.

Onto answered 28/10, 2022 at 14:59 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Conventional
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewSilici

© 2022 - 2024 — McMap. All rights reserved.