---
title: "client.labels"
description: "Every method in this namespace: its signature, its parameters, what it returns and an example."
url: "https://openemail.uk/docs/ruby/reference/labels"
area: "Ruby"
category: "Reference"
---

# client.labels

Every method in this namespace: its signature, its parameters, what it returns and an example.

## Methods

The labels a thread can carry.

### `labels.list`

List the workspace's labels, a page at a time

```ruby
list(limit: nil, cursor: nil, api_key: nil) -> OpenEmail::Page
```

Returns one page of the workspace's user labels, sorted by name and then by id. `list_all` collects every page and `iterate` walks them lazily. Each label carries its colour, `threadCount` (how many conversations carry it now) and `createdAt` and `updatedAt`, which is everything the Labels table in the app shows.

System labels such as `INBOX`, `STARRED` and `UNREAD` are not listed. A thread carries them and `threads.update` takes them, but they cannot be renamed, recoloured or deleted.

`color` is nil on a label saved with no colour. Otherwise `color[:backgroundColor]` is a hex value or a gradient token such as `gradient:sunset`, and `color[:textColor]` is the ink the app draws on it, worked out on the server rather than stored.

Scopes: `labels:read`.

**Parameters**

- `limit` (`Integer`): Page size, from 1 to 100. The server defaults to 25.
- `cursor` (`String`): The `next_cursor` of the previous page, passed back as it came. Leave it out for the first page.
- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

An `OpenEmail::Page` of Hashes, with `items`, `has_more?` and `next_cursor`. Each item has `id`, `name`, `type`, `color`, `threadCount`, `createdAt` and `updatedAt`.

**Example**

```ruby
page = client.labels.list(limit: 50)

page.items.each { |label| puts "#{label[:name]} #{label[:threadCount]}" }

puts "more after #{page.next_cursor}" if page.has_more?
```

**Notes**

- Labels belong to the workspace, so a narrowed key still sees every label. `threadCount` is the exception: it counts only conversations delivered to the addresses the key holds.
- An id is fixed when the label is created and survives a rename, so match on `id` rather than `name` in stored configuration.
- The sidebar order in the app is each person's own arrangement and is not exposed.
- The cursor is opaque and holds where the last row sat in this order, so a row deleted or edited between pages never breaks the walk: the next page starts at the first row that sorts after it. A cursor this list did not hand out is a 400 `invalid_cursor`.

Also available in: API [`GET /labels`](https://openemail.uk/docs/api/reference/labels#get-labels); TypeScript [`labels.list()`](https://openemail.uk/docs/sdk/reference/labels#list); Python [`labels.list()`](https://openemail.uk/docs/python/reference/labels#list); CLI [`openemail labels list`](https://openemail.uk/docs/cli/reference/labels#labels-list).

### `labels.list_all`

Collect every label into one array

```ruby
list_all(limit: nil, cursor: nil, api_key: nil) -> Array<Hash>
```

Walks every page of `list` and returns all labels, sorted by name and then by id. One request per page.

Scopes: `labels:read`.

**Parameters**

- `limit` (`Integer`): Page size for each request, from 1 to 100. The server defaults to 25.
- `cursor` (`String`): Starts the walk after this cursor instead of the first page.
- `api_key` (`String`): Overrides the client API key for every page of this walk.

**Returns**

An Array of Hashes holding every label.

**Example**

```ruby
labels = client.labels.list_all(limit: 100)
receipts = labels.find { |label| label[:name] == "Receipts" }

client.threads.update("CAHk7pQ2x9LmZ4-mail.example.com", addLabelIds: [receipts[:id]]) if receipts
```

**Notes**

- If any page fails the call raises and the labels already fetched are discarded.

Also available in: API [`GET /labels`](https://openemail.uk/docs/api/reference/labels#get-labels); TypeScript [`labels.listAll()`](https://openemail.uk/docs/sdk/reference/labels#listAll); Python [`labels.list_all()`](https://openemail.uk/docs/python/reference/labels#listAll).

### `labels.iterate`

Stream the labels one at a time

```ruby
iterate(limit: nil, cursor: nil, api_key: nil, &block) -> Enumerator<Hash>
```

Returns an Enumerator that yields labels one at a time, sorted by name and then by id, and requests the next page only once the current one is drained. Given a block, it yields each label to the block instead. Nothing is fetched until you consume it, and breaking out of the loop stops the requests.

Scopes: `labels:read`.

**Parameters**

- `limit` (`Integer`): Page size for each request, from 1 to 100. The server defaults to 25.
- `cursor` (`String`): Starts the walk after this cursor instead of the first page.
- `api_key` (`String`): Overrides the client API key for every page of this walk.

**Returns**

An Enumerator of Hashes, one label per step (or yields each one to a block).

**Example**

```ruby
client.labels.iterate do |label|
  puts "unused #{label[:name]}" if label[:threadCount] == 0
end
```

**Notes**

- The Enumerator is lazy, so an abandoned loop costs only the pages you consumed.

Also available in: API [`GET /labels`](https://openemail.uk/docs/api/reference/labels#get-labels); TypeScript [`labels.iterate()`](https://openemail.uk/docs/sdk/reference/labels#iterate); Python [`labels.iterate()`](https://openemail.uk/docs/python/reference/labels#iterate).

### `labels.list_colors`

List the colours the app offers for labels

```ruby
list_colors(api_key: nil) -> Array<Hash>
```

Returns the whole label palette as a plain Array: the fourteen solid colours and seven gradients the app offers when you make or edit a label, in the order it shows them. It is a fixed catalogue, so there is no paging. Fetch it once and keep it.

`value` is what to send as `color.backgroundColor`: a hex such as `#3B82F6` for a solid, a token such as `gradient:sunset` for a gradient. `textColor` is the ink drawn on it. A gradient also carries `from` and `to`, drawn at 135 degrees, and `solid`, one hex for places a gradient cannot go.

A label may carry a colour outside this list. Any hex set through the API is kept as it is, and the app offers it back as its own swatch.

Scopes: `labels:read`.

**Parameters**

- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

An Array of Hashes, each with `kind`, `name`, `value`, `solid`, `from`, `to` and `textColor`.

**Example**

```ruby
colors = client.labels.list_colors
sunset = colors.find { |color| color[:name] == "sunset" }

client.labels.create(name: "Launch", color: {backgroundColor: sunset ? sunset[:value] : "#EF4444"})
```

**Notes**

- `kind` is `solid` or `gradient`. `from` and `to` are nil on a solid.

Also available in: API [`GET /labels/colors`](https://openemail.uk/docs/api/reference/labels#get-labels-colors); TypeScript [`labels.listColors()`](https://openemail.uk/docs/sdk/reference/labels#listColors); Python [`labels.list_colors()`](https://openemail.uk/docs/python/reference/labels#listColors); CLI [`openemail labels list-colors`](https://openemail.uk/docs/cli/reference/labels#labels-list-colors).

### `labels.get`

Read one user label by id

```ruby
get(id, api_key: nil) -> Hash
```

Looks up a single user label and returns it in the same shape as a row of `list`, with its colour, `threadCount`, `createdAt` and `updatedAt`.

Only user labels are served. `INBOX`, `TRASH` and the other system ids are a 404 here even though threads carry them. Ids are matched exactly, so `user_receipts` does not find `USER_RECEIPTS`.

Scopes: `labels:read`.

**Parameters**

- `id` (`String`, required): Label id such as `USER_RECEIPTS`, matched case sensitively.
- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

A Hash with `id`, `name`, `type` set to `user`, `color`, `threadCount`, `createdAt` and `updatedAt`.

**Example**

```ruby
label = client.labels.get("USER_RECEIPTS")

puts label[:name], label.dig(:color, :backgroundColor) || "no colour", label[:threadCount]
```

**Notes**

- A missing label raises `OpenEmail::NotFoundError`, an `OpenEmail::ApiError` with `not_found?` true and code `resource_not_found`.

Also available in: API [`GET /labels/{id}`](https://openemail.uk/docs/api/reference/labels#get-labels-id); TypeScript [`labels.get()`](https://openemail.uk/docs/sdk/reference/labels#get); Python [`labels.get()`](https://openemail.uk/docs/python/reference/labels#get); CLI [`openemail labels get`](https://openemail.uk/docs/cli/reference/labels#labels-get).

### `labels.create`

Create a user label

```ruby
create(body = nil, api_key: nil, **fields) -> Hash
```

Creates a label and returns it as it is stored. `name` is trimmed and must then be 1 to 225 characters. The id is derived from the name as `USER_` followed by the name upper cased, with each run of whitespace turned into `_`, so `Big Clients` becomes `USER_BIG_CLIENTS`, and it never changes afterwards.

A name another label already has, compared without case, is refused with 409 `label_name_taken`, and so is a name whose id another label holds because it was created under that name and renamed since. An existing label is never silently overwritten. A workspace holds at most 50 user labels, and the call past that is a 422 `label_limit_reached` on `name`.

`color` is optional. `color.backgroundColor` is a hex colour (`#RGB`, `#RGBA`, `#RRGGBB` or `#RRGGBBAA`, stored upper cased) or a gradient token such as `gradient:sunset`, and anything else is a 422 `invalid_parameter` on `color.backgroundColor`. `list_colors` returns the palette the app offers. `textColor` may be sent but is ignored: the ink is worked out from the background. Leaving `color` out stores no colour.

Scopes: `labels:write`.

**Parameters**

- `name` (`String`, required): Display name, trimmed, 1 to 225 characters. Also decides the id.
- `color` (`Hash`): The colour. Leave it out for a label with no colour.
- `color.backgroundColor` (`String`): A hex colour such as `#3B82F6` or a gradient token such as `gradient:sunset`, at most 32 characters. Required once `color` is given.
- `color.textColor` (`String`): Accepted and ignored. The ink is worked out from `backgroundColor`.
- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

A Hash with the new `id`, the trimmed `name`, `color`, `threadCount` of 0, `createdAt` and `updatedAt`.

**Example**

```ruby
label = client.labels.create(name: "Big Clients", color: {backgroundColor: "gradient:aurora"})

puts label[:id], label.dig(:color, :textColor)
```

**Notes**

- The SDK does not retry a create after a network failure. If you retry by hand after a lost response, a 409 `label_name_taken` means the first attempt succeeded.

Also available in: API [`POST /labels`](https://openemail.uk/docs/api/reference/labels#post-labels); TypeScript [`labels.create()`](https://openemail.uk/docs/sdk/reference/labels#create); Python [`labels.create()`](https://openemail.uk/docs/python/reference/labels#create); CLI [`openemail labels create`](https://openemail.uk/docs/cli/reference/labels#labels-create).

### `labels.update`

Rename or recolour a user label

```ruby
update(id, patch = nil, api_key: nil, **fields) -> Hash
```

Renames a label, recolours it, or both, and returns it as it is stored. Send `name`, `color` or both: a field left out stays as it is, and a patch with neither is a 422. `color: nil`, or an empty `backgroundColor`, clears the colour.

The id never changes. A label created as `Receipts` keeps `USER_RECEIPTS` after a rename to `Invoices`, and every thread keeps the label. A new name another label already has, compared without case, is refused with 409 `label_name_taken`.

Colours follow the rules on `create`: a hex value or a gradient token, and anything else is a 422 `invalid_parameter`. Only user labels can be changed, and a system label id is a 404.

Scopes: `labels:write`.

**Parameters**

- `id` (`String`, required): Label id such as `USER_RECEIPTS`.
- `name` (`String`): New display name, trimmed, 1 to 225 characters. Left out, the name stays.
- `color` (`Hash or nil`): New colour. `nil` clears it, and leaving it out keeps the stored colour.
- `color.backgroundColor` (`String`): A hex colour or a gradient token, at most 32 characters. An empty string clears the colour.
- `color.textColor` (`String`): Accepted and ignored. The ink is worked out from `backgroundColor`.
- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

A Hash with the unchanged `id` and the new `name` and `color`.

**Example**

```ruby
saved = client.labels.update("USER_RECEIPTS", color: {backgroundColor: "#EA9602"})

puts saved[:id], saved[:name], saved.dig(:color, :backgroundColor)
```

**Notes**

- The SDK retries this call after a network failure, since the same patch sent twice leaves the same label.

Also available in: API [`PATCH /labels/{id}`](https://openemail.uk/docs/api/reference/labels#patch-labels-id); TypeScript [`labels.update()`](https://openemail.uk/docs/sdk/reference/labels#update); Python [`labels.update()`](https://openemail.uk/docs/python/reference/labels#update); CLI [`openemail labels update`](https://openemail.uk/docs/cli/reference/labels#labels-update).

### `labels.delete`

Delete a user label and remove it from every thread

```ruby
delete(id, api_key: nil) -> Hash
```

Deletes a user label and, in the same transaction, takes it off every thread that carried it. The threads are otherwise untouched, so a thread that was only filed under this label stays in whatever folder it was in.

There is no undo. Creating a label with the same name again produces the same id, but the threads it was removed from do not get it back. Only user labels can be deleted, and a system label id is a 404.

Scopes: `labels:write`.

**Parameters**

- `id` (`String`, required): Label id such as `USER_OLD_PROJECT`.
- `api_key` (`String`): Overrides the client API key for this call only.

**Returns**

A Hash with `object` set to `label`, the `id` and `deleted` set to true.

**Example**

```ruby
removed = client.labels.delete("USER_OLD_PROJECT")

puts removed[:id], removed[:deleted]
```

**Notes**

- The SDK does not retry a delete. A 404 on your own second attempt after a lost response means the first one worked.
- `get` first if you want to say how many conversations will lose the label: its `threadCount` is that number.

Also available in: API [`DELETE /labels/{id}`](https://openemail.uk/docs/api/reference/labels#delete-labels-id); TypeScript [`labels.delete()`](https://openemail.uk/docs/sdk/reference/labels#delete); Python [`labels.delete()`](https://openemail.uk/docs/python/reference/labels#delete); CLI [`openemail labels delete`](https://openemail.uk/docs/cli/reference/labels#labels-delete).
