Upload a scanned file to a draft
Attach the file to your current message in Complexity. Select the draft's own mailbox and enable uploadDraftAttachment. The tool adds that scanned file to an editable canonical draft.
The actor needs mail.draft.attachment.add, based on mail.draft.edit, a MailGen license, a separate tool grant, enabled run tools, and an active owned mailbox. The model supplies only {draftId, attachmentId}. It cannot supply bytes, a URL, storage key, or provider override. Creating or editing draft content does not upload attachments.
Signed AdminService access binds the source to the run's direct parent user message and clean scan state. The worker rechecks current grant, scope, source ownership, and exact storage key. The tool cannot upload files from another turn or chat.
The source byte limit is 25 MiB. The signed command contains IDs and SHA-256 values. The backend checks the digest after a bounded storage read.
m365local and m365Ent use shared microsoft-graph/drafts/draft-attachments.ts. Files below 3 MB use Graph fileAttachment POST. Larger files use an upload session with sequential chunks below 4 MB. Provider credentials are not sent to the preauthenticated upload URL. Prisma and other providers explicitly reject this action. Complete Microsoft setup.
The draft hash uses subject/content/contentType/to/cc/bcc in the same order and defaults as removal. The complete attachment manifest, including inline items, has a separate baseline. This hash does not make the remote mutation atomic. A concurrent edit can occur between preflight and POST.
Uncertain upload results
Attachment POST is not idempotent. Before remote mutation, the worker saves a compare-and-set marker in syncOperation.desiredState. It includes baseline attachment IDs, exact source ID, and byte hash. After that marker, the same operation can only read back or reconcile. It cannot POST again.
Only a new attachment outside the baseline with an exact byte-hash match proves success. Filename and size alone do not. No match or multiple matches produce DRAFT_ATTACHMENT_UPLOAD_OUTCOME_UNCERTAIN. This can also follow a crash between marker persistence and POST, even when no remote attachment exists.
Inspect the draft and original operation before requesting a new upload. Blind retry could duplicate it. accepted means queued, not provider-confirmed. See attachment removal for the separate delete flow.