# 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](https://m7.org/docs/sdk/m7-identity/cli/organization-access.md#installation-and-release-boundary).
This PHP operation is separate from the CLI executable command inventory.

```php
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](https://m7.org/docs/api/api.user.m7.org/account.md)
and [website email use](https://m7.org/docs/sdk/m7-identity/website/account-emails.md). 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.
