---
title: "Mark read or starred, or move a message"
method: PATCH
path: "/v1/email/messages/{messageId}"
tags: ["Email"]
---

# Mark read or starred, or move a message

`PATCH /v1/email/messages/{messageId}`

## Request

- Base URL: `https://zernio.com/api`
- URL: `https://zernio.com/api/v1/email/messages/{messageId}`
- Auth: HTTP bearer

`folder` moves the message. On Google a move swaps the inbox, trash and spam labels and keeps every other label; `archive` removes the inbox label.

## Path parameters

- `messageId` string, required

## Request body

- EmailMessagePatch
  - `accountId` string, required
  - `unread` boolean
  - `starred` boolean
  - `folder` string: Well-known folder name or folder id to move into.

## Response `200`

The updated message. A move on Microsoft changes the message id; read it from `data.id`.

- object
  - `data` EmailMessage
    - `id` string: The provider's message id.
    - `threadId` string
    - `accountId` string
    - `provider` 'google' | 'microsoft'
    - `folders` string[]
    - `from` EmailAddress
      - `email` string, email, required
      - `name` string, nullable
    - `to` EmailAddress[]
      - `email` string, email, required
      - `name` string, nullable
    - `cc` EmailAddress[]
      - `email` string, email, required
      - `name` string, nullable
    - `bcc` EmailAddress[]
      - `email` string, email, required
      - `name` string, nullable
    - `replyTo` EmailAddress[]
      - `email` string, email, required
      - `name` string, nullable
    - `subject` string
    - `snippet` string
    - `text` string, nullable
    - `html` string, nullable
    - `attachments` EmailAttachment[]
      - `id` string
      - `filename` string
      - `contentType` string
      - `size` integer
      - `isInline` boolean
      - `contentId` string, nullable
    - `headers` object: Only with `includeHeaders=true`.
    - `raw` string: MIME source, only with `raw=true`.
    - `date` string, date-time
    - `unread` boolean
    - `starred` boolean
    - `metadata` object

## Other responses

- `400`: Invalid request
- `401`: Missing or invalid API key. `code` is `missing_credentials` when no Authorization header was sent and `invalid_credentials` when the key is unknown, revoked or expired.
- `404`: Resource not found
- `412`: The connected account cannot serve this request until something outside the request changes. Two codes: - `account_scope_missing`: the account was connected without the area this endpoint needs (`details.grantedAreas`, `details.missingArea`), or Google reports the grant lacks a permission. Reconnect with a wider `scopes=`. - `admin_consent_required` (Microsoft): the tenant requires an administrator's approval. `details.adminConsentUrl` is the Microsoft Entra admin-consent link to hand to one; it opens in a browser with no API key and stays valid for one hour. `GET /v1/connect/microsoft/admin-consent` mints a fresh one.

## Changes

- **2026-10-27** `0a24331f5431`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/zernio/apis/zernio-api/changes/v1/email/messages/:messageId/patch.md)

---

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