# Uploads

Insert, import, send and the draft routes also take media and multipart uploads on /upload/gmail/v1, up to 1 MiB.

Gmail's client libraries send a message as an upload when it carries a media body, so the simulator serves the `/upload/gmail/v1` routes beside `/gmail/v1`. Insert a message as raw `message/rfc822` bytes, then as a multipart body with its labels, send one and meet the size cap:

```bash
curl -s -X POST "$RYSTIC_URL/_rystic/scenario" -d '{"name":"gmail_busy_inbox"}' -o /dev/null
G=(-H 'Authorization: Bearer ya29.placeholder')
MSG=$'From: ada.lovelace@example.com\r\nTo: marcus.bell@northwind.example\r\nSubject: Uploaded\r\n\r\nBy upload.\r\n'
printf '%s' "$MSG" | curl -s "$RYSTIC_URL/upload/gmail/v1/users/me/messages?uploadType=media" "${G[@]}" -H 'Content-Type: message/rfc822' --data-binary @- | jq -c '{labelIds}'
# -> {"labelIds":[]}
printf -- '--b\r\nContent-Type: application/json\r\n\r\n{"labelIds":["INBOX","UNREAD"]}\r\n--b\r\nContent-Type: message/rfc822\r\n\r\n%s\r\n--b--\r\n' "$MSG" | curl -s "$RYSTIC_URL/upload/gmail/v1/users/me/messages?uploadType=multipart" "${G[@]}" -H 'Content-Type: multipart/related; boundary=b' --data-binary @- | jq -c '{labelIds}'
# -> {"labelIds":["INBOX","UNREAD"]}
printf '%s' "$MSG" | curl -s "$RYSTIC_URL/upload/gmail/v1/users/me/messages/send?uploadType=media" "${G[@]}" -H 'Content-Type: message/rfc822' --data-binary @- | jq -c '{labelIds}'
# -> {"labelIds":["SENT"]}
curl -s "$RYSTIC_URL/gmail/v1/users/me/messages?labelIds=UNREAD&q=subject:uploaded" "${G[@]}" | jq -c '{resultSizeEstimate}'
# -> {"resultSizeEstimate":1}
curl -s "$RYSTIC_URL/_rystic/version" | jq -c '{blob_cap_bytes}'
# -> {"blob_cap_bytes":1048576}
head -c 1100000 /dev/zero | tr '\0' 'a' | curl -s "$RYSTIC_URL/upload/gmail/v1/users/me/messages?uploadType=media" "${G[@]}" -H 'Content-Type: message/rfc822' --data-binary @- -o /dev/null -w '%{http_code}\n'
# -> 413
```

### Which routes take an upload

Insert, import and send take an upload, and so do a draft's create, update and send. Both forms are served on each route:

- `uploadType=media` carries the `message/rfc822` bytes alone.
- `uploadType=multipart` carries a JSON metadata part, then the message, in one `multipart/related` body.

A media `drafts.send` carries no draft `id` and returns 400 `invalidArgument`, "Invalid draft". A multipart one takes the `id` in its metadata part ([Drafts](https://www.rystic.ai/docs/simulators/gmail/features/drafts.md)).

**Differs from Gmail:** an insert by media upload returns a `snippet` member that Gmail leaves out ([Limitations](https://www.rystic.ai/docs/simulators/gmail.md#limitations)).

**Differs from Gmail:** an import by upload returns a `labelIds` member beside its id, where Gmail returns the id alone ([Limitations](https://www.rystic.ai/docs/simulators/gmail.md#limitations)).

### The size cap

An upload's body holds up to 1 MiB, and a larger one returns 413. `GET /_rystic/version` reports the cap as `blob_cap_bytes`. A message sent as base64url `raw` in JSON has no such cap.

**Differs from Gmail:** Gmail takes an upload of up to 150 MB on insert and import, but only 35 MB on send and the draft routes.

---

Source: https://www.rystic.ai/docs/simulators/gmail/features/uploads · Markdown: https://www.rystic.ai/docs/simulators/gmail/features/uploads.md
