17

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!

Paulo Salgado
  • 437
  • 4
  • 14

7 Answers7

14

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
Roman Kazakov
  • 697
  • 7
  • 12
  • Interesting. I'll try that. Thanks! – Paulo Salgado Aug 14 '20 at 11:33
  • 1
    This worked for me. I implemented it in python and have put that in a separate answer. – xanatos Jun 23 '21 at 20:29
  • 3
    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 payload](https://api.slack.com/reference/messaging/payload) – ahollenbach Jul 09 '21 at 00:11
  • 2
    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. – ZaxR Apr 22 '22 at 14:39
  • 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? – Mark Dominus Jul 14 '22 at 16:46
  • I posted [a question about this here](https://stackoverflow.com/questions/72984528/how-to-upload-a-text-file-to-slack-without-sharing-it-to-a-channel), but if you have any thoughts I'd be glad to hear them. – Mark Dominus Jul 14 '22 at 19:25
  • @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. – Chris Hayes Jul 21 '22 at 17:58
6

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",
)
vilozio
  • 111
  • 1
  • 8
xanatos
  • 170
  • 1
  • 8
3

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)

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.

Chris Hayes
  • 11,505
  • 6
  • 33
  • 41
  • 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 nodejs – Izlia Nov 29 '22 at 20:26
  • 1
    @Izlia 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. https://api.slack.com/methods/files.upload/code – Chris Hayes Nov 29 '22 at 22:39
  • 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 it – Izlia Dec 05 '22 at 07:03
  • 1
    @Izlia 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. – Chris Hayes Dec 05 '22 at 07:27
  • 1
    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? – Izlia Dec 05 '22 at 07:59
  • @Izlia 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. – Chris Hayes Dec 05 '22 at 09:33
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

Philip
  • 31
  • 4
0

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
                )
-1

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

Kim K
  • 39
  • 5
  • 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](/help/how-to-answer). – Community Nov 02 '22 at 17:45
  • 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 Review](/review/late-answers/33053444) – Thomas Smyth - Treliant Nov 03 '22 at 17:08