# Extract OTP and 2FA codes from email

Source: https://developer.nylas.com/docs/cookbook/cli/extract-otp-codes/

OTPs are the single most annoying thing in test automation: a CI runner can't open Gmail to grab a six-digit code. The [Nylas CLI](https://cli.nylas.com/) has two commands that solve this — [`nylas otp get`](https://cli.nylas.com/docs/commands/otp-get) for a single fetch and [`nylas otp watch`](https://cli.nylas.com/docs/commands/otp-watch) for a streaming poll loop. Both work across every provider Nylas supports.

This recipe covers single-shot capture, scripted CI usage, and the watch mode for long-running flows.

## Grab the latest code

```bash
nylas otp get
```

That command scans recent messages on the active grant, identifies a verification code, and copies it to your clipboard. The whole round-trip is sub-second on a healthy mailbox.

For scripts and CI, you want the value on stdout instead of the clipboard:

```bash
CODE=$(nylas otp get --raw)
```

`--raw` returns the bare code with no formatting, so you can drop it into the next command without parsing.

## A typical CI flow

```bash
# Trigger the signup
curl -X POST https://api.example.com/signup -d '{"email":"qa@example.com"}'

# Give the verification email a moment to land
sleep 3

# Pull the code
CODE=$(nylas otp get --raw)

# Hand it back to the API
curl -X POST https://api.example.com/verify -d "{\"code\":\"$CODE\"}"
```

This pattern eats the entire problem — your tests no longer need a fixture inbox, a mocked provider, or a per-environment SMTP server. They just point at a real Nylas-managed grant and read the code.

## Watch for codes as they arrive

For long-running flows where you don't know when the OTP will land:

```bash
nylas otp watch --interval 5
```

The watcher polls the inbox every 5 seconds and prints each new code as it arrives. Pipe it through `head -n 1` to grab just the next one and exit:

```bash
NEXT_CODE=$(nylas otp watch | head -n 1)
```

Authentication scales the same way: drop `NYLAS_API_KEY` into the environment of an ephemeral CI runner and `nylas otp get` works without a config file.

## Across providers

The OTP commands abstract over Gmail, Microsoft 365, Exchange (EWS), Yahoo Mail, iCloud Mail, and any IMAP server you've connected. The matching logic — currently 6-digit numerics with sender heuristics — sits in the Nylas backend, so you don't tune regex per provider.

## Things to know

- **The active grant matters.** [`nylas otp get`](https://cli.nylas.com/docs/commands/otp-get) reads from whatever account [`nylas auth list`](https://cli.nylas.com/docs/commands/auth-list) shows as current. Switch with [`nylas auth switch`](https://cli.nylas.com/docs/commands/auth-switch).
- **Recency window.** The CLI considers messages from the last few minutes only. Older codes won't match — you don't want yesterday's GitHub OTP picked up by today's signup test.
- **Multiple codes in one message.** When more than one number-shaped string appears, the CLI prefers the one closest to phrases like "verification code", "OTP", or "PIN". For pathological mail formats, fall back to a custom regex over `nylas email read --raw`.

## Next steps

- [Sign up for a service](/docs/cookbook/agent-accounts/sign-up-for-a-service/) — the Agent Accounts version
- [E2E email testing with Playwright](/docs/cookbook/use-cases/build/e2e-email-testing/)
- [Nylas CLI](https://cli.nylas.com/) — installation and full [command reference](https://cli.nylas.com/docs/commands)