---
title: "Download one file from inside a received zip or tar attachment"
method: GET
path: "/emails/{id}/attachments/{attachment}/members/{path}"
tags: ["Emails"]
---

# Download one file from inside a received zip or tar attachment

`GET /emails/{id}/attachments/{attachment}/members/{path}`

## Request

- Base URL: `https://api.primitive.dev/v1`
- URL: `https://api.primitive.dev/v1/emails/{id}/attachments/{attachment}/members/{path}`
- Auth: HTTP bearer

Returns the decoded bytes of one regular file inside a zip, tar or tar.gz attachment, by its listed path. The archive's structure, every member path and every limit are checked as for the listing, but only the requested file is decoded and verified (its zip CRC-32, and X-Content-SHA256 of the bytes returned); list the archive to have every file decoded. Authenticate with an organization API key, an authorized organization OAuth token, or an address-bound agent connection key. A connected agent reads only mail received at its own address. Function credentials are not supported. Discarded content is unavailable.

## Response `200`

Decoded bytes of the archive member

## Other responses

- `400`: Invalid request parameters
- `401`: Invalid or missing API key
- `403`: Authenticated caller lacks permission for the operation
- `404`: Missing or inaccessible message, no such attachment, or no regular file at this path.
- `409`: attachment_name_ambiguous: more than one attachment has this filename, or a digits-only path value matches no part_index but is the name of an attachment; error.details.part_indexes lists every match, so fetch by part_index or by ?filename=. Or attachment_changed: attachment metadata changed during the read.
- `410`: content_discarded
- `413`: archive_limit_exceeded, or attachment_limit_exceeded for the attachment itself. Limits: at most 1000 entries of any kind (files, directories and links all count); each file at most 31457280 bytes decoded; all files together (for tar.gz, the whole decoded tar stream) at most 33554432 bytes; a compression ratio above 100:1 is refused once decoded output passes 1048576 bytes; member paths at most 1024 UTF-8 bytes. Any limit exceeded is 413 archive_limit_exceeded.
- `422`: attachment_not_archive, archive_unsafe_path, archive_invalid or archive_unsupported. The format is detected from the content, not the filename: zip, tar, or tar inside gzip. An archive with an absolute, drive-letter, backslash, control-character, Unicode format or separator character (bidirectional controls included), empty, "." or ".." path segment is refused whole (422 archive_unsafe_path) rather than listed without the entry. Any symbolic or hard link is refused the same way (422 archive_unsafe_path), wherever it points. Paths that differ only by letter case or Unicode normalization count as duplicates. Duplicate paths, overlapping zip data, a zip local header whose name or method disagrees with the central directory, and truncated or corrupt structures are 422 archive_invalid; encryption, zip64, multi-volume archives, compression other than stored or deflate, sparse tar files, and device or other special files are 422 archive_unsupported. Directories are validated and counted but neither listed nor served.
- `429`: Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.
- `502`: attachment_integrity_failed
- `503`: attachment_not_ready, attachment_storage_unavailable or archive_busy; see Retry-After. archive_busy: this server is already reading as many archives as it allows at once. Nothing is wrong with the archive; retry after Retry-After.

## Changes

> 32 revisions in range; 1 not diffed.

- **2026-11-03** `bce409c97acb`: 341 warning
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `400`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `401`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `403`
  - added the new `access_mode_unavailable` enum value to the `error/code` response property for the response status `404`
  - …337 more
  - …this revision’s changelog is incomplete
- **2026-10-21** `0360ea8d4f3d`: 143 warning
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `400`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `401`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `403`
  - added the new `agent_changed` enum value to the `error/code` response property for the response status `404`
  - …139 more
- **2026-10-21** `5279a7bed7ac`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/primitive/apis/primitive-api/changes/emails/:id/attachments/:attachment/members/:path/get.md)

---

[API](https://skmtc.dev/primitive/apis/primitive-api.md) - [All operations](https://skmtc.dev/primitive/apis/primitive-api/llms.txt) - [OpenAPI document](https://skmtc.dev/primitive/apis/primitive-api/revisions/bce409c97acb?raw)
