Source: https://cli.nylas.com/guides/if-match-gmail-api

Guide

# Gmail API ETag, If-Match, and history.list

Exact answers for Gmail API ETag, If-Match, If-None-Match, messages.get, 304 Not Modified, and history.list when deleting labels. Also points to a provider-neutral alternative if you do not want to hand-roll mailbox sync.

Written by [Qasim Muhammad](https://cli.nylas.com/authors/qasim-muhammad) • Staff SRE

Reviewed by [Nick Barraclough](https://cli.nylas.com/authors/nick-barraclough)

Updated April 11, 2026

Verified

 —

CLI

3.1.1

 ·

Gmail

 ·

last tested

April 11, 2026

> **Scope note:** this page answers the exact Gmail API questions showing up in Search Console: whether `users.messages.get` has an`etag`, whether Gmail documents `If-Match` or `If-None-Match`, what `304` and `412` mean here, and how `history.list` relates to label deletion.

## Exact answers to the top Gmail API queries

These are the exact search intents driving impressions to this page. The short answers below are based on Google's Gmail API reference and sync guide, not on generic HTTP advice.

| Query | Short answer | Source |
| --- | --- | --- |
| `gmail api etag` | The documented Gmail `Message` schema includes `historyId` but does not document an `etag` field. | [Message resource](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.messages) |
| `gmail.users.messages.get if-none-match` | The `users.messages.get` method page documents path params and response shape, but it does not document `If-None-Match` or a `304` contract. | [users.messages.get](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.messages/get) |
| `gmail api if-match` | Gmail's method docs do not document `If-Match` behavior for message or label endpoints, so do not rely on it as a Gmail-specific concurrency contract. | [Gmail REST reference](https://developers.google.com/workspace/gmail/api/reference/rest) |
| `delete a label history.list gmail` | `history.list` documents label changes on messages, not a label resource deleted event. Refresh `users.labels.list` after deleting custom labels. | [history.list](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.history/list) |

## Does users.messages.get return an etag field?

Not in the documented JSON resource. Google's `Message` reference lists fields such as `id`, `threadId`, `labelIds`, `snippet`, and `historyId`. It does not list an `etag` property. That matters because many search queries assume Gmail exposes a stable message ETag in the resource body. The docs do not support that assumption.

If your HTTP client exposes response headers, treat that separately from the documented Gmail resource schema. The safe, Gmail-specific change marker in the official docs is `historyId`.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://gmail.googleapis.com/gmail/v1/users/me/messages/$MESSAGE_ID?format=metadata&fields=id,threadId,labelIds,historyId,snippet" \
  | jq

# Documented response fields look like:
# {
#   "id": "18c7...",
#   "threadId": "18c7...",
#   "labelIds": ["INBOX", "UNREAD"],
#   "historyId": "442991",
#   "snippet": "Preview text..."
# }
```

## What Gmail documents about If-Match, If-None-Match, 304, and 412

General HTTP docs explain what `If-Match`, `If-None-Match`, `304 Not Modified`, and `412 Precondition Failed` mean. Gmail's own method pages are narrower: the reference for `users.messages.get`, `users.messages.modify`, `users.labels.patch`, and `users.labels.delete` does not document conditional request behavior for those headers.

- `If-None-Match` is not documented on `users.messages.get`.
- `If-Match` is not documented on the Gmail message or label methods most people search for.
- `304` and `412` are not described as part of the Gmail contract on those method pages.

> **Inference from the reference docs:** because the Gmail method pages do not document conditional header semantics on these endpoints, treat any observed `304` or `412` behavior as undocumented and non-portable unless Google adds endpoint-specific documentation.

In other words: use generic HTTP documentation as background knowledge, but build Gmail sync and concurrency around the behaviors Google actually documents for Gmail.

## How history.list actually relates to label deletion

`history.list` is Gmail's documented incremental sync mechanism. Google's sync guide says to store the latest `historyId`, then call `users.history.list` later with `startHistoryId`. If that start value is out of date or invalid, the API returns `404` and you must do a full sync.

The history response documents message-level change buckets such as `messagesAdded`, `messagesDeleted`, `labelsAdded`, and `labelsRemoved`. That means Gmail history is very useful when a label is added to or removed from a message. It is not documented as a change feed for the label catalog itself.

```bash
curl -H "Authorization: Bearer $TOKEN" \
  "https://gmail.googleapis.com/gmail/v1/users/me/history?startHistoryId=$START_HISTORY_ID" \
  | jq '.history[] | {id, messagesAdded, messagesDeleted, labelsAdded, labelsRemoved}'

# If START_HISTORY_ID is too old, Gmail returns HTTP 404.
# At that point, do a full sync and store a newer historyId.
```

## What to do after deleting a custom Gmail label

If you call `users.labels.delete` to remove a custom label, do not wait for a documented "label deleted" event from `history.list`. The Gmail history reference does not describe one. The safer pattern is:

1. Delete the custom label with the Labels API.
2. Refresh the label catalog with `users.labels.list`.
3. Reconcile any missing label IDs in your local cache.
4. Continue using `history.list` for message-level changes.

```bash
# Refresh the current label catalog after deleting a custom label
curl -H "Authorization: Bearer $TOKEN" \
  "https://gmail.googleapis.com/gmail/v1/users/me/labels" \
  | jq '.labels[] | {id, name, type}'

# Compare the returned IDs to your cached label list.
# Missing IDs are deleted labels.
```

## The safer Gmail architecture to build around

If you are building directly on Gmail, the documented path is straightforward:

- Use `historyId` and `history.list` for incremental sync.
- Expect a `404` fallback path when the stored `startHistoryId` ages out.
- Re-fetch the label catalog separately when label definitions change.
- Avoid depending on undocumented Gmail-specific ETag semantics for correctness.

If you need a provider-neutral alternative, the rest of this site shows how to push mailbox events through Nylas so the same integration pattern works across Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP without hand-rolling each provider's sync edge cases.

## Next steps

- [Gmail Message resource](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.messages) - the documented fields for `users.messages.get`
- [Gmail history.list reference](https://developers.google.com/workspace/gmail/api/reference/rest/v1/users.history/list) - documented history buckets and `startHistoryId` behavior
- [Gmail sync guide](https://developers.google.com/workspace/gmail/api/guides/sync) - Google's documented incremental sync flow and 404 fallback
- [Command reference](https://cli.nylas.com/docs/commands) - Nylas CLI commands for mail, calendars, webhooks, and MCP
- [Gmail API Pagination and Sync](https://cli.nylas.com/guides/gmail-api-pagination-sync) - next page tokens, history windows, and sync fallbacks
- [Why Gmail API Breaks AI Agents](https://cli.nylas.com/guides/why-gmail-api-breaks-ai-agents) - quotas, OAuth friction, and retry overhead
- [List Gmail Emails](https://cli.nylas.com/guides/list-gmail-emails) - inspect Gmail data without writing API client code first
- [Give AI Agents Email Access via MCP](https://cli.nylas.com/guides/ai-agent-email-mcp) - use one MCP surface across mail providers
