Attach files

Add files to a ticket through a comment, what the 20 MiB limit and the content check refuse, which files open inline, and who can download an attachment.

Written for
user
Roles
owner, admin, member, project-manager, elevated-client-user, client-user
Requires
Anyone who may comment on the ticket at the chosen audience
Feature
tickets

Files are attached to a ticket through the comment composer, or arrive with an email. Every attachment belongs to a ticket, has an audience like a comment, and is checked before it is kept. There is no separate file area: attachments live in the ticket's timeline.

Before you start

You need to be able to write a comment on the ticket at the audience you choose. The audience rules are in Comment on a ticket. Uploads are limited to 30 per minute per person.

Steps

  1. Open the ticket and go to Write a comment.
  2. Choose the Audience first. The file takes the audience selected at the moment you pick it.
  3. Select Attach a file and choose a file of at most 20 MiB. The file is uploaded at once and listed as a chip under the text box. Repeat for more files, up to 20 per comment.
  4. Write a comment if you want (a comment may consist of attachments only) and select Comment.

Rules

  • Size. At most 20 MiB per file. Empty files are refused.

  • Quarantine and content check. An upload is held in quarantine while SAQ inspects its bytes. The type the browser or sender declares is never trusted: the file's real content decides what it is and whether it is kept.

  • Refused files. A file is refused when it is:

    • an executable, installer, or launcher by content (programs, shared libraries, Windows installers, Java archives, Debian, RPM, and Android packages, Windows shortcuts, registry files);
    • a script by extension, since scripts are plain text the content check cannot see through: .exe .dll .com .scr .pif .cpl .msi .msp .bat .cmd .ps1 .psm1 .vbs .vbe .js .jse .wsf .wsh .hta .jar .sh .reg .lnk .app .dmg .pkg .deb .rpm .apk;
    • a mismatch: declared as an image or PDF while its content is something else;
    • oversize: over 20 MiB.

    In the app the upload fails with "That kind of file is not accepted." or "Attachments are limited to 20 MiB." and nothing is stored. When an email brings a refused file, the message is still processed and the timeline records "refused the attachment invoice.exe: executable files are not kept" (or "script files are not kept", "the content does not match its declared type", "it is over the size limit").

  • Inline or download. PNG, JPEG, GIF, WebP, AVIF, and PDF files open in the browser when selected. Every other type is downloaded. SVG and HTML files are never shown inline, whatever their name says, and are served as plain downloads.

  • Audience. An attachment is visible, listed, and downloadable only to people who may read comments at its audience. When the comment is posted, its attachments take the comment's final audience.

  • Where attachments appear. Attachments posted with a comment are listed under that comment. Attachments without a comment (uploaded but never posted, or arrived by email) are listed above the timeline with their audience badge.

  • Filenames. Names are kept up to 200 characters; slashes and control characters are replaced.

  • Redaction and deletion. Redacting a ticket replaces every attachment with the marker [redacted] and removes the file; deleting a ticket removes its attachments. See Archive and delete a ticket.

Examples

A client user attaches a screenshot to a Shared comment on their ticket. The support engineer opens the PNG inline and answers in the same thread.

A colleague sends a .zip by email to the ticket's thread; the archive is kept as a download. The .exe in the same email is refused and the timeline says so.

Attach through the API

Upload first, then reference the file in a comment:

curl -X POST https://saq.no/api/w/acme/tickets/ACME-184/attachments \
  -H "Authorization: Bearer saq_YOUR_TOKEN" \
  -F "file=@report.pdf" \
  -F "audience=internal"

The response includes the attachment id. Then POST /api/w/acme/tickets/ACME-184/comments with {"body": "Report attached.", "audience": "internal", "attachmentIds": ["01924c3e-6b2a-7d11-9d0e-3a1f4b5c6d7e"]}. An attachment can only be attached to a comment on the same ticket by the person who uploaded it. Download with GET /api/w/acme/attachments/{id}. Details in the API reference.

Common problems

  • "That kind of file is not accepted." The file is an executable, has a script extension, or its content does not match its declared type. Zip it, or share it another way.
  • "Attachments are limited to 20 MiB." Compress the file or split it.
  • "The file is empty." The chosen file has no content.
  • "An attachment does not belong to this ticket." The API call referenced an attachment uploaded to another ticket or by another person.
  • A colleague cannot see the file I attached. The attachment has an audience they may not read (for example Staff for an elevated client user). Attach it again to a comment at a wider audience.