Read a consumer account's email list

Availability: verified Token/PHP 0.1.4 ZIP. It includes the Emails classes. Install the complete archive and autoload layout described in package installation. This PHP operation is separate from the CLI executable command inventory.

use M7\Identity\M7IdentitySDK;

$report = (new M7IdentitySDK())->accountEmails($apiUserBundle, [
    'expected_sub' => $verifiedConsumerSubject,
]);
if (!$report->ok()) {
    throw new RuntimeException($report->reason() ?? 'Account email request failed');
}
$emails = $report->emails();

accountEmails(array bundle, array options): AccountEmailsReport reads the existing API User GET/POST /api/v2/account/me/email/list route. It does not create an SSO endpoint. Use an API User consumer access bundle with an accepted API User audience (https://api.user.m7.org or https://user.m7.org) and account.me.email.list, plus live principal/session and sender-binding checks. The caller acquires/exchanges that bundle. SSO email is not permission for it. Standard SSO userinfo() with openid email separately supplies primary email/email_verified when available; no /userinfo/emails or separately advertised SSO email-list endpoint exists.

Inputs and transport

The bundle follows authenticated request(): access_token, optional token_type, and required fingerprint state. Pending bundles are rejected; refresh-only lineage is never sent. A DPoP bundle needs a caller-created proof for this API User URI, actual method and access token. Do not reuse an SSO proof.

Closed options are expected_sub (required trusted consumer ID), endpoint (optional trusted HTTPS override without credentials/query/fragment), method (POST default or GET), dpop, fingerprint, client_certificate, connect_timeout, timeout, and max_response_bytes. Defaults are 5 seconds, 10 seconds and 65,536 bytes. Unknown/configuration inputs fail before transport. POST sends an empty JSON object and response mode is always JSON. TLS, redirect/body/time bounds, certificate/proof/fingerprint transport and nonce handling use ResourceRequestClient.

Result validation

Require a successful API User JSON envelope (status 1, "1" or true) and data containing a list or null (the existing empty repository result). Every row needs a UUID id, uid exactly matching expected_sub, a nonempty whitespace/control-free email, and boolean or numeric/string 0/1 verified and primary_email. Reject archived, malformed, foreign, duplicate-ID (case-insensitive), or multiple-primary records. This checks projection, not email deliverability; verification remains an explicit provider assertion.

The client returns only id, email, boolean verified and boolean primary. Owner IDs, timestamps, vendor fields and record metadata are omitted. A valid empty list has no echoed subject; no provider sub is invented from caller input. Every failure exposes an empty email list.

AccountEmailsReport exposes ok(), reason(), httpStatus(), emails(), errorDescription(), headers(), header(name), dpopNonce() and toArray(). Bounded errors and nonce challenges support explicit caller recovery; tokens and proofs are absent. This operation does not refresh/exchange, generate proofs, retry, own sessions or persist/cache results. Optional validation/key caches elsewhere in the SDK are separate.

See API User account management and website email use. Current-source AccountEmailsTest covers request construction, binding, safe fields, empty/failure/malformed results and sender-constraint handling; no immutable release or live deployment claim follows from those tests.