---
title: "Helpers and constants"
description: "What else the gem defines besides the client."
url: "https://openemail.uk/docs/ruby/reference/helpers"
area: "Ruby"
category: "Reference"
---

# Helpers and constants

What else the gem defines besides the client.

## Module methods

| Method | What it is |
| --- | --- |
| `OpenEmail.init`, `OpenEmail.client` | Configure the shared client once, then reach it from anywhere. It builds itself from `OPENEMAIL_API_KEY` if `init` never ran. |
| `OpenEmail.emails`, `OpenEmail.threads` and every other namespace | Shortcuts to the namespaces of the shared client. |
| `OpenEmail.reset_client` | Drops the shared client, so the next call builds a fresh one, which is what a test wants between cases. |
| `OpenEmail.create_client`, `OpenEmail::Client.new`, `OpenEmail.new` | A separate client. `create_client` reads the environment for anything you leave out, and `Client.new` (or `OpenEmail.new`) takes only what you pass. |
| `OpenEmail.create_temp_mail` | A disposable-inbox client that carries no API key. |
| `OpenEmail.verify_webhook_signature` | Checks a delivery’s signature in constant time, with a replay window. Returns the parsed event, and raises `OpenEmail::WebhookSignatureError` on any failure. |
| `OpenEmail.to_base64` | Base64 for attachment bytes, from a binary String, an IO or a Pathname. |
| `OpenEmail.api_key?` | Whether a String has the `oe_live_` or `oe_test_` shape. A shape check, not proof the key still works. |
| `OpenEmail.access_token?` | Whether a String has the shape of an OAuth access token: 1 to 512 characters, not beginning `oe_`. |
| `OpenEmail.sealed?` | Whether a message’s body is ciphertext. It is false for the two signed formats, whose bodies arrived in the clear. |
| `OpenEmail.resolve_language`, `OpenEmail.language_by_code`, `OpenEmail.rtl_language?` | The lookups a language picker needs, over the bundled `OpenEmail::LANGUAGES` table. |

## Constants

Every value set the TypeScript SDK exports is a frozen Hash on `OpenEmail`, keyed by the same names, so `OpenEmail::WEBHOOK_EVENTS[:EMAIL_DELIVERED]` is `"email.delivered"`. Use `.values` where you need the list, and `.value?` to check a value that came from outside.

**constants.rb**

```
events = OpenEmail::WEBHOOK_EVENTS.values

scopes = [OpenEmail::API_SCOPES[:EMAILS_SEND], OpenEmail::API_SCOPES[:THREADS_READ]]

puts events.size, scopes.join(","), OpenEmail::PAGE_LIMITS[:MAX_LIMIT]
```

| Constant | What it holds |
| --- | --- |
| `OpenEmail::VERSION` | The gem version. |
| `OpenEmail::API_SCOPES` | The scope vocabulary, for a key-creation screen. |
| `OpenEmail::WEBHOOK_EVENTS`, `OpenEmail::WEBHOOK_SIGNATURE_HEADERS` | The events an endpoint can subscribe to, and the names of the headers a delivery carries. |
| `OpenEmail::ERROR_TYPES` | The error vocabulary that `ApiError#type` takes. |
| `OpenEmail::PAGE_LIMITS` | The largest and the default `limit:` on most paged lists: 100 and 25. A few lists take more, and each method’s reference says so. |
| `OpenEmail::RULE_FIELDS`, `OpenEmail::RULE_OPERATORS`, `OpenEmail::RULE_ACTIONS` | The vocabulary a rule’s conditions and actions are built from. |
| `OpenEmail::MESSAGE_ENCRYPTION_FORMATS` | The five envelopes ingest can name. Three of them are sealed. |
| `OpenEmail::CREDENTIAL_KINDS`, `OpenEmail::STEP_UP_METHODS`, `OpenEmail::STEP_UP_ERROR_CODES` | Which credential `me.get` and `me.ping` describe, how a verification code is checked, and the codes a verification can fail with. |
| `OpenEmail::THREAD_SORTS`, `OpenEmail::PEOPLE_SORTS`, `OpenEmail::FILE_SORTS` and the other `*_SORTS` | The orders a list can be sorted in. |
| `OpenEmail::FORM_STATUSES`, `OpenEmail::BROADCAST_STATUSES`, `OpenEmail::SUPPRESSION_REASONS` and the other sets | The values a field of a resource can take. Each set is named after what it holds. |

## Objects

A response is the parsed JSON as a Hash with Symbol keys. The gem builds an object of its own only where it shapes the answer, and each is an immutable `Data`.

| Class | What it carries |
| --- | --- |
| `OpenEmail::Page` | `items`, `has_more?` and `next_cursor`, from every paged `list`. |
| `OpenEmail::PeoplePage` | The same plus `seen`, from `contacts.list_people`. |
| `OpenEmail::TempMessagesPage` | The same plus `expires_at`, from `temp_mail.list_messages`. |
| `OpenEmail::AddressBookPage`, `OpenEmail::AddressBook` | `unrestricted`, `addresses` and `domains`, from `addresses.list` (with `has_more?` and `next_cursor`) and `addresses.list_all`. |
| `OpenEmail::BatchResult` | `items`, `sent` and `failed`, from `emails.send_batch`. |
| `OpenEmail::TemplateSends` | `items`, `total`, `page` and `page_size`, from `templates.list_sends`. |
| `OpenEmail::HttpRequest`, `OpenEmail::HttpResponse` | What an `adapter:` receives and returns. A request prints its `Authorization` header as `[redacted]`. |

> Every error the gem raises on purpose inherits from `OpenEmail::Error`: `ApiError` and its subclasses, `NetworkError` and `WebhookSignatureError`. A wrong argument is an `ArgumentError` instead, because it is a mistake in the calling code rather than something to rescue.

## An endpoint this does not wrap yet

A gem release should never be what stands between you and an endpoint that already works. `client.raw.request` takes a path and keyword options and returns the parsed body, with the client’s credential, base URL, timeout and retry policy applied.

**escape_hatch.rb**

```
result = client.raw.request(
  "/something-new",
  method: :post,
  query: {dryRun: true},
  body: {name: "Invoices"},
  repeatable: true
)

p result
```

> A GET is retried like any other read. Any other method is sent once unless you pass `repeatable: true`, which is your assertion that it may be sent twice. `query:` skips values that are nil or empty, and `api_key:` works as it does on every other method.

## What it deliberately does not do

- It validates no request body. The server’s schema is the only copy of the rules, and a second copy here would eventually refuse an address a newer server accepts, in a version somebody pinned two years ago.
- It has no runtime dependencies, not even a JSON or HTTP gem beyond the standard library.
- It reshapes a response in one way only: a collection’s `data` array is lifted out of its envelope into one of the objects above. Every other response comes back as the API sent it, with the API’s camelCase keys.

> The gem’s parity check keeps this honest. It fails the build when a TypeScript method has no Ruby twin, takes different options, or sends a different request.
