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

# Exit codes

> What jetemail returns to your shell, and how to read errors.

The CLI uses a small, deliberate set of exit codes so it composes cleanly in shell pipelines and CI.

| Code | Meaning                                                          |
| ---- | ---------------------------------------------------------------- |
| `0`  | Success                                                          |
| `1`  | Error (network failure, HTTP non-2xx, validation, bad arguments) |

Errors print the HTTP status and parsed response body to **stderr**. Stdout stays clean, so you can pipe successful runs into `jq` without filtering noise.

## Examples

```sh theme={null}
jetemail outbound domains list && echo "ok"
# ok

jetemail outbound domains delete bogus-uuid
# HTTP 404: { "error": "domain not found" }
# (exit 1)

if ! jetemail send --to ops@example.com --from alerts@example.com --subject "deploy ok" --text "deploy ok"; then
  echo "alert delivery failed" >&2
  exit 1
fi
```

## CI: fail the build on errors

```yaml theme={null}
- name: Sync suppression list
  env:
    JETEMAIL_API_KEY: ${{ secrets.JETEMAIL_API_KEY }}
  run: |
    jetemail outbound suppression import @suppressions.csv
```

The step fails automatically if the upload returns a non-2xx; no extra check needed.

## Distinguishing client vs. server errors

For one bit (`0` / `1`) the CLI returns, the body on stderr carries the detail. Parse it programmatically with `2>` redirection if you need to branch on the HTTP status:

```sh theme={null}
jetemail outbound domains check $UUID 2>/tmp/jetemail.err
if [ $? -ne 0 ]; then
  grep -q '"status":429' /tmp/jetemail.err && retry_with_backoff
fi
```
