Message Attachments
Message attachments are handled by the message command group. Use this for files or inline images that are attached to a Teams chat or channel message. Use teams file only when you want to manage the channel file library directly.
Send inline images
Inline images are uploaded as Teams hosted content and are rendered in the message body.
teams message send --chat "$CHAT_ID" --image ./screenshot.png --output json
teams message send \
--team "$TEAM_ID" \
--channel "$CHANNEL_ID" \
--body "Screenshot attached" \
--image ./screenshot.png \
--output json
--image is repeatable, and --body is optional when at least one image or file is supplied. Media messages are sent as HTML; a text body is escaped before the CLI adds the image or attachment markup.
Each inline image must be 3 MB or smaller. Because all hosted images share one Graph JSON request, their combined base64-encoded size must also remain at or below 4 MB. Use --attach for larger images.
Send file attachments
File attachments are uploaded first, then referenced from the Teams message. Chat attachments are stored in the sender's OneDrive Microsoft Teams Chat Files folder. Channel attachments are stored in the team's SharePoint-backed files area.
teams message send --chat "$CHAT_ID" --body "Report attached" --attach ./report.pdf --output json
teams message send \
--team "$TEAM_ID" \
--channel "$CHANNEL_ID" \
--body "Logs attached" \
--attach ./logs.zip \
--output json
File attachments use Microsoft Graph's simple-upload path and are limited to 250 MB per file. Uploads use rename-on-conflict behavior, so an existing file with the same name is not overwritten.
Chat attachments are shared with the members
A chat attachment lands in your own OneDrive, where nobody else has access. The Teams client grants
every member of the chat read permission when it attaches a file, and the CLI does the same after
each upload through the drive item's invite action, with no notification email. A member is
addressed by Entra object ID when the chat roster shows the same tenant as yours, and by email
otherwise — a chat's membership can span tenants, and an object ID means nothing outside its own
directory. You are skipped.
Every step is best-effort. A failed roster lookup, a member with no usable address, or a refused
grant warns on stderr and says to share the file from OneDrive by hand; the upload and the message
still go through. Reading the roster needs a chat-member read scope such as Chat.ReadBasic, which
the default set's Chat.ReadWrite covers. Channel attachments are unchanged: they live in the
team's SharePoint library, which channel members already read.
Reply to channel messages with attachments
Channel replies support the same --image and --attach flags as top-level messages.
teams message reply \
--team "$TEAM_ID" \
--channel "$CHANNEL_ID" \
--message "$MESSAGE_ID" \
--body "Adding the trace" \
--attach ./trace.txt \
--image ./detail.png \
--output json
List attachments
Use message get --with-attachments when you want a channel message payload and attachment metadata together.
teams message get --team "$TEAM_ID" --channel "$CHANNEL_ID" "$MESSAGE_ID" --with-attachments --output json
Use message attachments list when an automation only needs attachment metadata.
teams message attachments list --chat "$CHAT_ID" "$MESSAGE_ID" --output json
teams message attachments list \
--team "$TEAM_ID" \
--channel "$CHANNEL_ID" \
--reply "$REPLY_ID" \
"$MESSAGE_ID" \
--output json
For a channel reply, the positional MESSAGE_ID is the parent thread message and --reply is the reply message ID.
The inventory can include hosted-content images, file references, code snippets, adaptive cards, and other attachment metadata. Every item has a stable index; check its downloadable field before downloading it.
Download attachments
Download all attachments into a directory:
teams message attachments download --chat "$CHAT_ID" "$MESSAGE_ID" --dir ./assets --output json
Download one attachment by index:
teams message attachments download --chat "$CHAT_ID" "$MESSAGE_ID" --index 0 --path ./image.png --output json
Write bytes to stdout when the surrounding script handles the destination:
teams message attachments download --chat "$CHAT_ID" "$MESSAGE_ID" --index 0 --path - > image.png
--path requires --index. When --path - is used, stdout contains only the raw file bytes: the command deliberately does not print a JSON success envelope. File downloads are staged to a .part file and renamed atomically. When the CLI chooses the filename (no --path), unsafe filename characters are removed and an existing destination is preserved by adding a numeric suffix.
Required scopes
Inline hosted-content images use the same message permissions as reading or sending the message. File attachments require additional file permissions:
| Operation | Delegated scope |
|---|---|
| Read inline images | Same message-read scope |
| Download file attachments | Files.Read.All |
| Send chat file attachments, including sharing them with the members | Files.ReadWrite |
| Send channel file attachments | Files.ReadWrite.All |
Add scopes to the profile that needs the capability, then refresh the token:
[profiles.attachments]
tenant_id = "common"
scopes = "User.Read Chat.ReadWrite ChannelMessage.Send ChannelMessage.Read.All Files.Read.All Files.ReadWrite Files.ReadWrite.All offline_access"
teams auth refresh --profile attachments
If the tenant requires admin consent, generate a scoped consent URL first:
teams auth consent-url --profile attachments