# Project send logs

Logs belong to a project. `/members/send-log/search` requires
`mail.log.search`; `/members/send-log/view` separately requires
`mail.log.view`. Both routes use `POST` JSON with the same Bearer credential
and [workspace selection](https://m7.org/docs/api/api.mail.m7.org/workspaces.md) as the send operation. A service
role does not grant access to every project's records.

## Search

Send `/members/send-log/search`:

```json
{"project_id":"<project-uuid>","status":"queued","limit":20}
```

| Field | Type | Required/default |
| --- | --- | --- |
| `project_id` | UUID string | Required for normal callers; configured app default follows the [sending rule](https://m7.org/docs/api/api.mail.m7.org/sending.md). |
| `status` | string | Optional exact value: `queued`, `sent`, or `failed`. |
| `recipient_email` | string | Optional exact-match recipient filter; trimmed, at most 320 bytes. |
| `limit` | integer | Defaults to 20; maximum 100. Values below 1 reset to the default. |
| `cursor` | string | Optional opaque cursor returned by the prior page. |
| `offset` | integer | Optional nonnegative offset. |
| `page_number` | integer | Optional page number starting at 1. |

An empty string for either filter omits that filter. A whitespace-only
recipient filter is invalid. Prefer one pagination selector; when more than
one is present, precedence is `cursor`, then `offset`, then `page_number`.
Use the same filters and limit while paging. Offset-based pages can change
as new attempts arrive.

The response envelope's `data` contains `project_id`, `items`, `limit`,
`total_count`, `next_offset`, `page_number`, `page_total`, and `next_cursor`.
Records sort newest first by creation time and ID. Pass the returned
`next_cursor` unchanged for the next page; `null` ends the search.
`next_offset` is returned even beyond the final page, so it is not an
end-of-results signal. Empty searches return `items: []` and `page_total: 0`.

Search items contain `id`, `owner`, `project_id`, `source`, `transport`,
`sender_email`, `recipient_email`, `subject`, `status`, `provider`,
`error_code`, `error_message`, `created`, and `modified`. Search results omit
message bodies, display names, Reply-To, and metadata. `owner` is the effective
principal recorded for the attempt; project authority governs current access.
Statuses describe stored attempt state, not an assured recipient-delivery
receipt.

## View a message record

Send `/members/send-log/view`:

```json
{"project_id":"<project-uuid>","id":"<send-log-uuid>"}
```

`id` is the log-record UUID returned by sending or search. The response
`data` is `{ "project_id": "<project-uuid>", "item": { ... } }`.
The detailed record also includes sender and recipient names,
`reply_to_email`, `body_text`, `body_html`, `provider_message_id`, and metadata
when available. Treat these as message content with the same privacy
requirements as the original email. A message ID is separate from the
log-record ID.

The same optional `status` and `recipient_email` filters can constrain view.
A record absent from the selected project or not matching those filters
returns `404`. Sending `owner`, `owner_scope`, `organization_id`, or `client_id`
as identity overrides returns `400`. Keep project and organization selection
explicit rather than constructing owner filters.

[Return to Mailbox](https://m7.org/docs/api/api.mail.m7.org/README.md).
