> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erdo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sent email

> Every email Erdo sends on your behalf is recorded — who it went to, what it said, whether it landed, and what it was about. Read it back over the API.

Erdo sends email for you all the time: an agent mails a weekly summary, an event
pipeline alerts your sales desk the moment a lead lands, an automation sends a
digest. Each of those is recorded as it happens, and the **sent email log** is
how you read that record back.

This matters most when something is automated. An alert that fires at 2am is
invisible unless you can go and look at it afterwards — and "did it actually go
out, and what did it say?" is the first question anyone asks when a notification
seems to have gone missing. The log answers it directly, scoped to your own
organization, so you can show it in your own product rather than sending people
to a mail provider's dashboard.

## What a record holds

Every audited send stores the recipient and display name, the subject, both the
plain-text and HTML bodies exactly as they were sent, the delivery outcome
(`pending`, `sent`, or `failed`), and the timestamps.

It also stores **context** — a small set of key/value tags describing what the
message was *about*. This is the part that makes the log genuinely queryable, and
it exists because the recipient is very often not the subject. A new-lead alert
is addressed to your sales desk, so filtering by recipient tells you nothing
about which lead it concerned. Tag the send instead:

```json theme={null}
{ "kind": "lead_alert", "lead_email": "ana@example.com" }
```

and "every email we've sent about Ana" becomes a real query rather than a
substring search over subject lines that breaks the moment someone rewords a
template. Context is never shown to the recipient.

<Note>
  Context values are flat text. Nested objects and arrays are dropped rather than
  stored, because the lookup that reads them back matches on flat key/value pairs —
  keeping them would advertise a query that could never work.
</Note>

## Reading the log

`GET /v1/emails` lists your organization's mail, newest first, filtered by
recipient (`to`), by time (`since`, an RFC 3339 timestamp), or by subject text
(`search`). Bodies are omitted from the listing so a page of results doesn't drag
a page of HTML documents with it.

```bash theme={null}
curl "https://api.erdo.ai/v1/emails?to=desk@example.com&limit=25" \
  -H "Authorization: Bearer $ERDO_API_KEY"
```

To filter by context, use `POST /v1/emails-query` — a query string can't carry a
key/value map, so the structured probe travels in a JSON body. The probe is a
**containment** match: name only the keys you care about and rows carrying those
plus others still match.

```bash theme={null}
curl -X POST "https://api.erdo.ai/v1/emails-query" \
  -H "Authorization: Bearer $ERDO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"context": {"lead_email": "ana@example.com"}}'
```

`GET /v1/emails/{emailID}` returns one message in full, including both bodies as
they were sent.

Listings report a `total` alongside the page, so you can page without having to
discover the end by requesting an empty result.

## Tagging what you send

The `send_email` action takes an optional `context` object, wherever you invoke
it — from an agent, from a `script.run` step on an event pipeline, or from a
scripted job:

```js theme={null}
actions.invoke("erdo", "send_email", {
  to: "desk@example.com",
  subject: "New lead: Ana",
  plain_text: body,
  context: { kind: "lead_alert", lead_email: "ana@example.com" },
});
```

It costs nothing to set and it is the difference between a log you can search and
one you can only scroll. Set it whenever the recipient isn't the subject of the
message.

Mail sent before context existed, and mail from senders that don't set it, simply
carries an empty context — treat it as optional on read, never as a guarantee.

## Access

The log is scoped to the organization of the caller, enforced in the query
itself. Requesting a message id belonging to another organization returns *not
found* — identical to an id that doesn't exist, so the endpoint can't be used to
probe for someone else's mail.

## Related

<CardGroup cols={2}>
  <Card title="Inboxes" href="/inboxes">
    The other direction — an address Erdo can *receive* at.
  </Card>

  <Card title="Event pipelines" href="/event-pipelines">
    Where lead-arrival alerts are usually sent from.
  </Card>
</CardGroup>
