Domains
`domains.list`, `get` and `update`.
Every method
const domains = await openemail.domains.list()const domain = await openemail.domains.get('b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6f') console.log(domain.receiving.verified, domain.sending.status)for (const address of domain.addresses) console.log(address.address, address.enabled) const updated = await openemail.domains.update(domain.id, { trackingHost: 'links.acme.com' })console.log(updated.tracking.status, updated.tracking.record?.name, updated.tracking.record?.value) await openemail.domains.update(domain.id, { trackingHost: null })Receiving and sending are two independent facts and are returned as two objects. receiving.verified means the domain’s MX brings its mail here and its ownership challenge is published. sending reports the outbound signing check: status is verified, pending, failed, no_identity or unknown, and canSend says whether a send from the domain would be accepted right now. A negative verdict older than a day is treated as unknown rather than as a refusal, so branch on canSend rather than on status.
update sets, checks again or removes the domain’s custom tracking domain, a subdomain such as links.acme.com, and resolves to the same DomainDetailResource as get. tracking reports it on every read. Until a check passes, tracking.status is pending and tracked links and the open pixel keep using the default OpenEmail host. Once one passes, it is active and new mail from the domain uses the tracking domain for both.
get also lists the addresses on the domain. addresses.list() is the related call: every address THIS KEY may put in a From header, which is narrower.
Parameters: domains.get
domainIdstringrequired- The id from `domains.list`, a UUID minted when the domain was added, not the hostname, so `get('example.com')` finds nothing. The lookup is scoped to the key's own connection as well as to the id, so another workspace's domain is a 404 rather than a 403.
Parameters: domains.update
idstringrequired- The same domain id `get` takes. `domains:write` is the scope it needs.
patch.trackingHoststring | nullrequired- A subdomain of the domain, at most 512 characters, such as `links.acme.com`. It is trimmed and lowercased, and a leading `https://` or `http://`, a path and a trailing dot are stripped. A new value is validated, saved and checked in the same call. The value the domain already has runs the check again, unless the last one was less than 30 seconds ago. `null` or an empty string removes the tracking domain.
A refused host throws an OpenEmailApiError naming trackingHost in param: 422 invalid_tracking_host for a name that cannot be used, such as one outside the domain, 409 domain_not_verified for a new host while receiving.verified is false and the domain’s _openemail-challenge TXT record is not published yet, and 409 tracking_host_in_use for a name another domain already uses, or when the tracking domain is managed by a different OpenEmail server. A key limited to specific addresses gets 422 capability_unsupported, because a tracking domain applies to every address on the domain.
Response: DomainDetailResource
object'domain'- Always the string `domain`, on `list` rows and on this one alike.
idstring- The domain's UUID. Stable for the life of the row, and the only handle the other domain calls accept.
domainstring- The bare hostname, lowercased: `example.com`. Unique across the whole product, one owner per domain, so two workspaces cannot both claim it.
receiving.verifiedboolean- True once DNS showed the domain’s MX naming a host that brings its mail here and, where the row carries a challenge token, the matching `_openemail-challenge` TXT record. MX alone proves nothing, since every domain we receive for publishes the same hostnames, which is why the token exists, and why this flag is the gate inbound delivery checks before accepting mail.
receiving.verifiedAtstring | null- When verification passed, ISO-8601. Null while it has not, and `verified` is derived from exactly this column, so the two can never disagree.
receiving.catchAllboolean- Whether any local-part is accepted. On by default for domains added since this became the rule; with it off only addresses named on the domain are accepted and the rest are rejected at SMTP time, so the sender gets a bounce rather than silence.
receiving.lastCheckedAtstring | null- When DNS was last asked about this domain. Null means never looked, which reads very differently from a failure to somebody who added a domain a minute ago. This endpoint reports the stored result, never running a check of its own.
receiving.errorstring | null- Why the last check did not pass, in words the owner can act on: `No MX records yet. DNS changes can take a few minutes to spread.` is a typical one. Null once it passes, and stored rather than derived so a reload and the scheduled re-check say the same thing.
sending.status'verified' | 'pending' | 'failed' | 'no_identity' | 'unknown'- The outbound signing state as the last check saw it. Read from the stored check rather than probed on this request, so `sending.checkedAt` says how old it is.
sending.canSendboolean- Whether a send from this domain would be accepted right now. A negative verdict older than a day is treated as unknown rather than as a refusal, so this can be true while `status` is `pending`. Branch on this before a send: a false one means `emails.send` from this domain is refused with a 409 `domain_not_sendable`.
sending.checkedAtstring | null- When the signing state was last checked, ISO-8601. Null means never, which reads very differently from a failure.
sending.errorstring | null- The last signing failure in words, or null once it passes.
sending.notestring- One of five sentences, chosen by `sending.status`, saying what that state means in words a domain owner can act on. Prose for a human to read. Branch on `sending.canSend` rather than on this.
trackingDomainTracking- The domain’s custom tracking domain, on `list` rows and on this one alike, and what `update` changes.
tracking.hoststring | null- The tracking domain, such as `links.acme.com`, or null when none is set.
tracking.status'none' | 'pending' | 'active' | 'failed'- `none` means no tracking domain is set, `pending` means it has never passed a check, `active` means new mail uses it, and `failed` means it passed before and has since dropped out of use. An active host drops out after three failed checks in a row, or once its last passed check is more than 2 hours old.
tracking.activeboolean- True exactly when `status` is `active`, which is when tracked links and the open pixel in new mail from the domain use the host.
tracking.targetstring- The address the CNAME record points at, prepared for this tracking domain alone. An empty string while `host` is null, and while the address for a new host is still being prepared.
tracking.record{ type: 'CNAME'; name: string; value: string } | null- The record to publish, named after `host` with `target` as its value. Null when there is no tracking domain, and while the address for a new host is still being prepared.
tracking.checkedAtstring | null- When the host was last checked, ISO-8601. Null until the first check.
tracking.verifiedAtstring | null- When a check last passed, ISO-8601. Null for a host that has never passed one.
tracking.errorstring | null- What the last check found, in words the domain owner can act on. Null when the last check passed or none has run yet. A host that has failed one or two checks is still `active` and carries the reason here.
addressesArray<{ address: string; enabled: boolean }>- Every address row on the domain, which is what `get` adds over a `list` row. It includes the rows delivery wrote itself under catch-all, and those stop being accepted the moment catch-all is turned off, so the array is not a list of what will receive.
addresses[].addressstring- The full address, rebuilt from the stored local-part and the hostname and lowercased, so it always matches the `domain` above rather than drifting from it.
addresses[].enabledboolean- False disables the address, and a disabled one is rejected even when catch-all is on. Every row is listed either way, so filter on this rather than reading the array as the set of working addresses.
createdAtstring- When the domain row was added, ISO-8601. Not when it verified: that is `receiving.verifiedAt`, which can be null while this is set.