
# Output and scripting

Every command prints a table or a short message for people. Add `--json` and it prints JSON for scripts instead.

## Rules scripts can rely on

- **Data goes to stdout; everything else goes to stderr.** Errors, `Wrote <path>` lines from `download`, the `(showing N; raise --limit for more)` note, and the `(cached — synced …)` note never mix into piped output.
- **Exit status** is 0 on success and 1 on any error. A `sync run` where some folders fail also exits 1, after syncing the rest.
- **`--json`** works on every mailbox and sync command. `emails filter` always prints JSON. Of the setup commands, only `config accounts list` has `--json`.
- **Destructive commands need `--yes`.** There are no interactive prompts, so a script never hangs waiting for input.

## JSON shapes

`emails list`, `emails search` and `drafts list` print an array of messages without bodies:

```json
[
  {
    "id": 1423,
    "messageId": "<inv-2291@vendor.example>",
    "from": { "name": "Vendor Billing", "addr": "billing@vendor.example" },
    "to": { "name": null, "addr": "you@example.com" },
    "subject": "Invoice INV-2291 for September",
    "date": "2026-10-01T09:12:44.000Z",
    "flags": [],
    "hasAttachment": true
  }
]
```

- `id` is the per-folder message ID. `to` is the first recipient only.
- `flags` holds IMAP flags such as `\Seen` (read), `\Flagged` and `\Answered`. An unread message has no `\Seen`.
- `date` is ISO 8601 in UTC.

`emails show --json` prints one full message: the same fields, plus `to` as an array of every recipient, `text`, `html`, and `attachments` (each with `filename`, `contentType` and `size` in bytes).

Other commands print a small result object. For example, `emails download --json` lists the saved files with `path`, `filename`, `contentType` and `size`.

## Choosing columns

`emails list` and `emails search` take `--fields` to choose and order table columns:

```bash
fob-email emails list --fields date,from,subject,attach
```

Fields are `id`, `from`, `to`, `subject`, `date`, `flags` and `attach`. `--fields` affects the table only; `--json` always prints every field.

## Filtering in a pipeline

`emails filter` reads a JSON array of messages on stdin and keeps the ones that match. It doesn't connect to your mailbox, so it's fast and works offline.

```bash
fob-email emails list --limit 200 --json \
  | fob-email emails filter --has-attachment --unseen
```

| Option | Keeps messages where |
| --- | --- |
| `--from <text>` | The sender's address or name contains the text |
| `--to <text>` | The recipient's address or name contains the text |
| `--subject <text>` | The subject contains the text |
| `--has-attachment` | There's at least one attachment |
| `--seen` / `--unseen` | The message is read / unread |

Matching ignores case, and every option you pass must match. Use `filter` for things server search can't do, such as "has an attachment".

## With jq

```bash
# IDs of unread messages from one sender
fob-email emails search --from billing@vendor.example --json \
  | jq -r '.[] | select(.flags | index("\\Seen") | not) | .id'

# A CSV of the newest 100 messages
fob-email emails list --limit 100 --json \
  | jq -r '.[] | [.id, .date, .from.addr, .subject] | @csv' > inbox.csv
```

More in [Recipes](/docs/email/cli/recipes).
