Downloading Attachments from a Sheet with API

Hello Smartsheet Community!

I need help downloading attachments from a sheet that currently has a little over five thousand lines and manually downloading isn't ideal.

I was able to extract the metadata for my sheet and revising the documentation for the Attachment Object I was able to extract the attachment id and other attributes but was missing the entire block which contained the url attribute.

I'm using python SDK with the code below

sheet = smartsheet_client.Sheets.get_sheet(sheet_id, include='attachments')

Alternatively I have also used

url = f"https://api.smartsheet.com/2.0/sheets/{sheet_id}?include=attachments"
headers = {
"Authorization": f"Bearer API CODE",
"Accept": "application/json"
}


response = requests.get(url, headers=headers)
if response.status_code == 200:
sheet_metadata = response.json()
print(json.dumps(sheet_metadata, indent=4)) # Pretty-print the JSON response
else:
print(f"Error: {response.status_code}, {response.json()}")

This is what my metadata is returning (example):

{
"id": 0,
"parentId": 0,
"attachmentType": "BOX_COM",
"attachmentSubType": "DOCUMENT",
"mimeType": "PNG",
"parentType": "COMMENT",
"createdAt": "2019-08-24T14:15:22Z",
"createdBy": {
"email": "jane.doe@smartsheet.com",
"name": "Jane Doe"
}

This is what should be returning:

{
"id": 0,
"parentId": 0,
"attachmentType": "BOX_COM",
"attachmentSubType": "DOCUMENT",
"mimeType": "PNG",
"parentType": "COMMENT",
"createdAt": "2019-08-24T14:15:22Z",
"createdBy": {
"email": "jane.doe@smartsheet.com",
"name": "Jane Doe"
},
"name": "string",
"sizeInKb": 0,
"url": "string",
"urlExpiresInMillis": 0
}

Without the url attribute I'm unable to use the get_attachment method.

Any idea what I'm doing wrong? Any help is truly appreciated.

Best Answer

  • jmyzk_cloudsmart_jp
    jmyzk_cloudsmart_jp Community Champion
    Answer ✓

    Hi @Jorge Ortiz

    As stated in the API document, include expect;

    A comma-separated list of optional elements to include in the response:

    https://smartsheet.redoc.ly/tag/sheets#operation/getSheet

    # Retrieve the sheet with attachments
    sheet_id,
    include=["attachments"]
    )

    Once you get the attachment object, get attachemt_id to use the Get Attachment method to get the Attachment temporary URL (files only).

    https://smartsheet.redoc.ly/tag/attachments#operation/attachments-get

    Here is a sample code that downloads all the row attachments.
    "Please note that this is only a demo code. You need to handle the rate limit for a sheet like yours with 5,000 rows (e.g., by adding a delay after every 300 API calls)

    import smartsheet
    import requests
    access_token = "Your access token"
    smartsheet_client = smartsheet.Smartsheet(access_token)

    # Set the sheet ID
    sheet_id = "Your Sheet ID"

    # Retrieve the sheet with attachments
    sheet = smartsheet_client.Sheets.get_sheet(
    sheet_id,
    include=["attachments"]
    )

    # Create a folder to store downloaded attachments
    import os
    download_folder = "attachments"
    if not os.path.exists(download_folder):
    os.makedirs(download_folder)

    print("--- Downloading Attachments ---")

    # Iterate through rows in the sheet
    for row in sheet.rows:
    # Check if the row has attachments
    if hasattr(row, 'attachments') and row.attachments:
    for attachment in row.attachments:
    if attachment.attachment_type == "FILE":
    # Get the attachment details
    attachment_id = attachment.id
    file_attachment = smartsheet_client.Attachments.get_attachment(
    sheet_id, # sheet_id
    attachment_id # attachment_id
    )

    # Download the file using the URL
    attachment_url = file_attachment.url
    file_name = file_attachment.name
    file_path = os.path.join(download_folder, file_name)

    print(f"Downloading attachment: {file_name} from {attachment_url}")

    # Download the file using the requests library
    response = requests.get(attachment_url)
    if response.status_code == 200:
    with open(file_path, 'wb') as file:
    file.write(response.content)
    print(f"File '{file_name}' downloaded successfully to '{file_path}'.")
    else:
    print(f"Failed to download the file '{file_name}'. HTTP Status: {response.status_code}")
    print("All attachments downloaded.")

Answers

  • jmyzk_cloudsmart_jp
    jmyzk_cloudsmart_jp Community Champion
    Answer ✓

    Hi @Jorge Ortiz

    As stated in the API document, include expect;

    A comma-separated list of optional elements to include in the response:

    https://smartsheet.redoc.ly/tag/sheets#operation/getSheet

    # Retrieve the sheet with attachments
    sheet_id,
    include=["attachments"]
    )

    Once you get the attachment object, get attachemt_id to use the Get Attachment method to get the Attachment temporary URL (files only).

    https://smartsheet.redoc.ly/tag/attachments#operation/attachments-get

    Here is a sample code that downloads all the row attachments.
    "Please note that this is only a demo code. You need to handle the rate limit for a sheet like yours with 5,000 rows (e.g., by adding a delay after every 300 API calls)

    import smartsheet
    import requests
    access_token = "Your access token"
    smartsheet_client = smartsheet.Smartsheet(access_token)

    # Set the sheet ID
    sheet_id = "Your Sheet ID"

    # Retrieve the sheet with attachments
    sheet = smartsheet_client.Sheets.get_sheet(
    sheet_id,
    include=["attachments"]
    )

    # Create a folder to store downloaded attachments
    import os
    download_folder = "attachments"
    if not os.path.exists(download_folder):
    os.makedirs(download_folder)

    print("--- Downloading Attachments ---")

    # Iterate through rows in the sheet
    for row in sheet.rows:
    # Check if the row has attachments
    if hasattr(row, 'attachments') and row.attachments:
    for attachment in row.attachments:
    if attachment.attachment_type == "FILE":
    # Get the attachment details
    attachment_id = attachment.id
    file_attachment = smartsheet_client.Attachments.get_attachment(
    sheet_id, # sheet_id
    attachment_id # attachment_id
    )

    # Download the file using the URL
    attachment_url = file_attachment.url
    file_name = file_attachment.name
    file_path = os.path.join(download_folder, file_name)

    print(f"Downloading attachment: {file_name} from {attachment_url}")

    # Download the file using the requests library
    response = requests.get(attachment_url)
    if response.status_code == 200:
    with open(file_path, 'wb') as file:
    file.write(response.content)
    print(f"File '{file_name}' downloaded successfully to '{file_path}'.")
    else:
    print(f"Failed to download the file '{file_name}'. HTTP Status: {response.status_code}")
    print("All attachments downloaded.")

  • jmyzk_cloudsmart_jp
    jmyzk_cloudsmart_jp Community Champion

    Happy to help!😁