How to Download Attachments From Your Export
Open the export, find the column called Attachments, and every cell in it holds a web address. Not a filename. Not a relative path pointing at a folder sitting next to the CSV you are reading — a full address, often three hundred characters long, ending in a query string of random-looking letters. Click the first one and the invoice opens in a new tab, correct and complete. That is the moment the export gets marked as done.
Click the same one on Thursday and it returns an error document.
The records and the files came out of two different systems on their way to you, and only one of them actually left the building. This is not a complaint about a particular vendor. It is the normal architecture, it is documented by the vendors themselves in pages nobody opens, and the gap it creates is measured in hours while the thing people plan around — the cancellation date — is measured in weeks.
Records and files leave through different doors
A record is a row. Exporting it means running a query, walking the result set and writing text; a few hundred thousand rows is a few tens of megabytes and finishes while you watch the progress bar.
An attachment is not in that database. It is an object in a storage bucket, and the row holds only a pointer plus some metadata: original filename, byte count, content type. To put the attachment in your ZIP the vendor has to read every object back out of storage, pay egress on all of it, hold it somewhere while the archive is assembled, and serve a download measured in gigabytes rather than megabytes. To put the pointer in costs nothing at all.
So most of them put the pointer in, and the honest ones say so on the page. Atlassian's article on exporting from Jira Cloud carries the sentence in its summary, above the instructions:
"Please note that Jira Cloud does not natively support downloading physical attachment files in bulk. For use cases involving physical attachment files, consider exporting their URLs via CSV as described below, or using third-party marketplace apps for bulk downloading attachments."
(Atlassian support, page updated 20 February 2026, read 7 September 2026)
Slack says the same thing in the first line of what your export contains: "After your export is complete, you'll download a ZIP file with your workspace data and a series of file links that direct back to your workspace's files" (Slack help centre, read 7 September 2026). Plan tiers change which conversations you are allowed to export at all, which is a separate set of rules worth reading before you rely on any of it, but the file behaviour does not move with the tier the way people expect it to.
Airtable describes the split in terms of the field type: the download URL property "links to those files and will expire every few hours," and the sentence that follows is not a footnote but the whole procedure — "We recommend downloading any attachments from the links in the exported CSV file before those links expire" (Airtable support, read 7 September 2026).
None of this surfaces as an error. Row counts are right, the file opens, the column is populated. The export is not broken; it is complete in exactly the way the vendor documented, and that documentation is the only place the distinction is written down.
The random string on the end is a clock
That long query string is a signature. The vendor's storage layer generated a URL granting access to one object, for a limited time, without anyone needing to log in, and the expiry time is baked into the string and signed along with it. Edit it and the signature stops matching.
The ceilings are set by the storage platforms and they are short by design. Amazon documents that when generating a presigned URL "using the console the maximum expiration time for a presigned URL is 12 hours from the time of creation", and that with the CLI "the maximum expiration time for a presigned URL is 7 days from the time of creation" (AWS S3 user guide, read 7 September 2026). Google Cloud Storage puts a hard number on the equivalent: "The longest expiration value is 604800 seconds (7 days)" (Google Cloud Storage documentation, read 7 September 2026). A week is the outer limit of the mechanism, not a setting anyone chooses. Vendors pick far less, because a link granting file access to whoever holds it is a liability that grows with its lifetime.
Airtable answers the duration question with a floor rather than a figure: "While Airtable may change this exact window, we will ensure that download URLs stay active for at least 2 hours after receiving them." The same page separates the two kinds of address the product hands out, and that is the distinction that catches people who test one link and generalise from it. Attachment viewer URLs live on the airtable.com domain and require base or interface access. Expiring download URLs live on airtableusercontent.com, need no Airtable access at all, and "will expire after a short time" for exactly that reason. The URL you copied out of your browser bar while logged in behaves nothing like the URL sitting in your CSV.
Asana's API reference is the shortest version of the whole problem. On the attachment download_url:
"If present, this URL may only be valid for two minutes from the time of retrieval. You should avoid
persisting this URL somewhere and just refresh it on demand to ensure you do not keep stale URLs"
(Asana API reference, read 7 September 2026).
Two minutes. Any dump that writes those URLs into a JSON file for later is producing a document that
was already wrong before it finished writing.
What each export actually hands over
| Vendor | Bytes in the download? | What the record export contains | Clock on it |
|---|---|---|---|
| Jira Cloud | No | Attachment URLs in the CSV | Vendor points you to third-party apps for bulk files |
| Slack | No | "A series of file links" in the ZIP | Links resolve against the workspace you are closing |
| Airtable | No | Filename plus expiring download URL | At least 2 hours, around 2 hours in practice |
| Asana (API) | No | download_url and permanent_url per attachment |
download_url may be valid for two minutes |
| Zendesk | Not described in the export article | content_url per attachment in the ticket JSON |
Export download link "valid for at least three days" |
| Trello (Premium Workspace) | Yes, with "Include raw attachments" | Without it, the export links to attachments hosted on Trello | Bundling is a paid-tier option, not the default |
| Notion | Yes | Assets saved into the ZIP alongside the pages | Emailed export link expires after 7 days |
| Google Workspace (admin export) | Yes | Real files, written per user into a bucket | Archive deleted 60 days from the start of the export |
Zendesk gets a hedge rather than a verdict, because the export documentation and the API
documentation answer different questions and neither answers this one head-on. The export article
describes a ZIP containing JSON, CSV or XML files, notes that exports are off by default and have to
be switched on by Zendesk support at the account owner's request, and states that "The download link
is valid for at least three days"
(Zendesk help centre, read 7 September 2026).
The attachment object appears in the API reference instead, as content_url, described as "A full
URL where the attachment image file can be downloaded," with a warning that "The file may be hosted
externally so take care not to inadvertently send Zendesk authentication credentials"
(Zendesk developer documentation, read 7 September 2026).
Run the export on your own account and count the files inside the ZIP before deciding which row you
are in.
The link that never expires and still dies with the account
There is a second kind of address, and it is more dangerous than the expiring one because it passes every test you are likely to run.
Asana documents it as permanent_url: "A stable URL for accessing the attachment through the Asana
web application. This URL redirects to the file download location (e.g., an S3 link) if the user is
authenticated and authorized to view the parent object (e.g., a task). Unauthorized users will
receive a 403 Forbidden response. This link is persistent and does not expire, but requires an active
session to resolve."
Read the last clause twice. The link is permanent. Your session is not. On the morning after cancellation that URL is still valid and still points at a real object, and it returns 403 to you forever, because what made it work was the login you gave up. Airtable's viewer URLs behave the same way: base or interface access required, dead once the record or the attachment is deleted.
Which is why "I clicked one and it opened" is not a test. A link that resolves while you are signed in as an admin is reporting on your session. It says nothing about what happens after the seat is removed, the plan drops to a free tier, or the workspace closes. The only test that means anything is opening the file from your own disk, signed out or in a private window, from a folder you control.
The bytes take days when the rows take minutes
The two-pipeline design shows up again in the timings, and this is where a cancellation date turns into a real constraint rather than an administrative one.
Notion, which does include the file bytes, warns that exports "can take up to 30 hours to process, depending on the size of the workspace," and that the emailed download link "will expire after 7 days" (Notion help centre, read 7 September 2026). Google's organisation-wide Workspace export is slower still: it "typically takes 72 hours but can take up to 14 days, depending on the size of your data export," the archive "is automatically deleted 60 days from the beginning of the export," and because the data comes out in packets rather than as one package, the advice for working out when any individual file disappears is to "subtract the number of days it took for the export to complete from 60" (Google Workspace admin help, read 7 September 2026). A 14-day export leaves 46 days of retrieval window, not 60.
So there are three clocks and they are not the same length. The job clock is how long the vendor takes to build the archive: minutes for records, up to two weeks for files at organisation scale. The link clock is how long the finished thing stays reachable — 7 days at Notion, at least three days at Zendesk, 60 days minus the job at Google, roughly two hours for a single Airtable download URL. And the account clock is the one you chose, the only one under your control, and the one most likely to have been set to the renewal date because that is when the billing stops.
Start the file half first. It is the slow half, it has the shortest link window once it finishes, and it is the only half that cannot be redone from a copy you already hold.
Fetching the bytes while the URLs are still warm
The mechanical part is not difficult. The order matters more than the tooling.
- Export the records in a format that keeps the attachment metadata, not just the URL. You want filename, byte count and content type in the same row as the link, because those three values are the only way to check later that what arrived is what was pointed at. Where the vendor offers a choice of formats, this is one of several reasons the structural format beats the readable one; the rest are in why a CSV is not a backup.
- Extract the URLs into a worklist immediately, with the record identifier beside each one. Not the name. The identifier, because names repeat.
- Fetch in one pass, straight away. Not tomorrow. If the vendor's window is two hours, a run starting ninety minutes after the export will fail its tail, and the failures land at the end of the file where nobody looks.
- Write each file into a path built from the record identifier, something like
attachments/<record_id>/<original_filename>. Original filenames collide constantly — every phone camera in the world producesIMG_0431.jpgand every scanner producesscan.pdf. Flatten them into one folder and the last download quietly overwrites the earlier ones. - Log the HTTP status and the received byte count for every fetch, into a CSV sitting next to the files. That log is what you reconcile against afterwards, and it is the only evidence you will have that a missing file was missing rather than never attempted.
- Re-run the export to refresh dead links; do not retry the same URL. An expired signature never comes back. Refreshing means going to the source for a new one, which is possible right up until the account closes and not one minute afterwards.
- Slow down before the vendor slows you down. A worklist of 40,000 attachments fired off at full concurrency looks like abuse from their side, and a throttling response is usually indistinguishable from an expiry error in your log.
The expensive mistake in this procedure is doing step 1 in week one and steps 3 to 6 on the last afternoon. The record export is durable and can sit on a disk for a month without harm. The URLs inside it cannot, and a CSV full of expired signatures is indistinguishable from a good one until somebody tries it.
Reconcile three numbers, then open the files
A fetch run that reports success is not evidence. Three checks turn it into evidence, and all three have to happen while you can still re-run the export.
Count. Attachment URLs in the export, against files on disk, against whatever count the vendor's own interface shows. If there is a storage-usage figure in the admin area, that is a third independent source. Resolve any mismatch before cancellation, because afterwards there is nothing left to compare against.
Bytes. Sum the byte counts recorded in the export metadata and compare against the size of the
folder. This is where the ugliest failure surfaces: an error response saved as though it were a file.
An expired S3 signature returns a small XML document with an AccessDenied code and an HTTP 403, and
a naive downloader saves that document under the filename it was expecting — a perfectly
plausible invoice-2026-0416.pdf holding a few hundred bytes of error text. A thousand of those look
like a successful run. Sort the folder by size ascending and they all appear together at the top,
suspiciously similar and far too small.
Open. Take ten and open them from disk, in a private window or with the desktop application rather than the vendor's viewer. Choose badly on purpose: the largest, the smallest non-zero, the oldest upload, the strangest extension, one uploaded by somebody who has since left, and one belonging to a record with several files rather than one. Ten files is five minutes, and it catches truncation, wrong content types and those error-text stubs in a way no count ever will.
Then keep the mapping. The fetch log — record identifier, original filename, stored path, byte count, status — is not a by-product, it is the index that makes the folder searchable in three years when somebody asks which file was attached to which invoice. Without it, a directory of correctly downloaded attachments is just weight, and keeping a retired system readable turns out to be mostly a question of whether that index exists.
What one more month of subscription actually buys
The asymmetry is worth stating plainly, because it is the argument that reliably wins a budget conversation about a tool you have already decided to leave.
While the subscription is live, every failure on this page is cheap. Links expired mid-run: export again. Attachments not bundled on your tier: Trello puts its "Include raw attachments" option behind a Premium Workspace, and one month at that price costs less than a day spent clicking through records one at a time. Export disabled for your account: an admin switches it on, or in Zendesk's case the account owner asks support to enable exports at all. Rate limited: run it across two nights.
After cancellation each of those becomes a support request to a company you no longer pay, and most of them stop being slow and start being impossible, because the account whose session made the URLs resolve does not exist any more. That gap — trivial before, impossible after — is why the attachment fetch belongs near the front of a cutover plan rather than in the tidy-up phase, and why the cancellation itself is the last thing to schedule instead of the first.
Verified against vendor documentation on 7 September 2026. Behaviour varies by plan and by product and changes without changelogs, so open the page matching your own tool before relying on any line above: Atlassian on exporting Jira Cloud issues to CSV (page updated 20 February 2026); Slack on reading data exports; Airtable attachment URL behaviour; Asana's attachments API reference; Zendesk on exporting ticket, user or organization data and its ticket attachments API reference; Atlassian on exporting data from Trello; Notion on exporting your content; Google Workspace admin help on exporting all your organization's data; AWS on sharing objects with presigned URLs; and Google Cloud Storage signed URLs.
Salesforce's weekly data export and its handling of Files and Attachments is a common question here and is deliberately absent above, because the help article would not load for checking on the date this was written. If a claim on this page has drifted from its source, the contact page reaches me, and corrections get re-checked and re-dated.
Frequently asked questions
Why are the attachments missing from my export?
Because most exports serialise database rows and reference files rather than bundling them. Jira Cloud states it directly: it "does not natively support downloading physical attachment files in bulk" and suggests "exporting their URLs via CSV" instead. Slack describes its ZIP as containing workspace data "and a series of file links that direct back to your workspace's files". Airtable says the download URL property "links to those files and will expire every few hours". Nothing failed in any of those cases and no error was shown — the attachment column contains addresses, and an address is only a file for as long as the vendor answers it.
How long do exported attachment links stay valid?
Hours in the common case, and the vendor rarely commits to a number. Airtable's FAQ answers the question with a floor rather than a value: "While Airtable may change this exact window, we will ensure that download URLs stay active for at least 2 hours after receiving them," and elsewhere on the same page it puts the practical figure at about two hours. Asana's API reference is shorter still: the attachment downloadurl "may only be valid for two minutes from the time of retrieval". The upstream ceilings explain the shape — an Amazon S3 presigned URL generated in the console maxes out at 12 hours and by CLI at 7 days, and a Cloud Storage signed URL has a longest expiration value of 604,800 seconds. Plan in hours, and check your own file before you plan at all.
Will the attachment links in my export still work after I cancel?
Assume not, including the links a vendor calls permanent. Asana's permanenturl is described as "a stable URL for accessing the attachment through the Asana web application" that "redirects to the file download location (e.g., an S3 link) if the user is authenticated and authorized to view the parent object", with unauthorized users receiving 403 Forbidden — persistent, but resolved through a session you are about to give up. Airtable's viewer URLs require base or interface access and stop working when the record is deleted. A URL that resolves while you are logged in is telling you about your login, not about your archive.
How do I download all the attachments in bulk?
There are three routes and you pick by what the vendor offers. Some exports ship the bytes: Notion's ZIP "will also include folders of images and other assets contained in these pages", and a Google Workspace organisation-wide export writes real files into a Cloud Storage bucket. Some vendors gate the bytes behind a tier: Trello's Workspace export offers an "Include raw attachments" option that returns files "in their original formats within a ZIP file in your download", and it takes a Premium Workspace — without that option, exports "will link to attachments hosted on Trello". Where neither exists, you extract the URLs from the export and fetch them with a script while they are still warm, which is what Airtable recommends: "downloading any attachments from the links in the exported CSV file before those links expire." Jira's own suggestion for that third case is a marketplace app.