Guide
Send OTP and 2FA Codes by Email
You need to email a one-time verification code from a script, a test, or an internal tool — without standing up SMTP. This guide generates a cryptographically secure code, sends it with one command across major providers, tests the full round trip, and is honest about where email OTP falls short.
Written by Pouya Sanooei Software Engineer
Reviewed by Qasim Muhammad
How do I send a one-time code by email from the terminal?
You send a one-time code by passing it to nylas email send with the recipient, a subject, and a body — the command delivers over your connected provider's API, so there's no SMTP host, port, or TLS certificate to configure. The --yes flag skips the confirmation prompt for unattended scripts.
CODE="492018"
nylas email send \
--to user@example.com \
--subject "Your verification code" \
--body "Your code is $CODE. It expires in 10 minutes." \
--yesThat single command replaces a Postfix relay, an app password, and the DNS records a self-hosted mailer needs. It works the same across Gmail, Outlook, Yahoo, iCloud, and any IMAP account, so the same script delivers codes regardless of which provider the sending account uses.
How do I generate a secure 6-digit code?
Generate the code from an operating-system cryptographic RNG, never from $RANDOM or a time seed. A predictable code defeats the whole point of a second factor. Python's secrets module draws from the OS CSPRNG and formats a zero-padded 6-digit value in one line, giving 1,000,000 possible codes.
# Cryptographically secure 6-digit code (1,000,000 possibilities)
CODE=$(python3 -c "import secrets; print(f'{secrets.randbelow(1000000):06d}')")
echo "$CODE"Six digits is the convention HMAC-based one-time passwords use in RFC 4226 (HOTP), balancing usability against brute-force resistance when paired with a short expiry and an attempt limit. Store a hash of the code with a timestamp server-side — never the plaintext — and compare on verify.
How do I test the full OTP round trip?
Test the round trip by sending a code to a connected inbox, then reading it back with nylas otp get --raw, which extracts the latest verification code in under a second. This turns a flaky, provider-specific E2E step into two commands and removes 20–50 lines of custom IMAP polling from your test harness.
#!/usr/bin/env bash
set -euo pipefail
CODE=$(python3 -c "import secrets; print(f'{secrets.randbelow(1000000):06d}')")
MY_ADDR="you@example.com" # the connected inbox 'nylas otp get' reads
nylas email send --to "$MY_ADDR" \
--subject "Your verification code" \
--body "Your code is $CODE." --yes
sleep 3
RECEIVED=$(nylas otp get "$MY_ADDR" --raw)
[ "$CODE" = "$RECEIVED" ] && echo "round trip OK" || echo "mismatch: $RECEIVED"Is email a secure channel for one-time codes?
Email is a convenient OTP channel but a weak authenticator, and you should know exactly why before relying on it. The U.S. NIST guidelines in SP 800-63B do not recognize email as an approved out-of-band authentication channel, because the inbox is often protected by the same password the code is meant to back up. Email OTP suits low-risk verification and testing, not high-value account protection.
Where you do use it, enforce three controls: a short expiry (5–10 minutes), a hard attempt limit (5 tries, then lock), and per-recipient rate limiting so an attacker can't trigger a flood of codes. Treat the emitted code as a one-time secret — single-use, then invalidated even if unused.
How do I send codes at scale without SMTP?
At scale, the CLI sends over provider APIs, so you skip the SMTP infrastructure that breaks under load and after auth changes. Microsoft retired Basic Auth in October 2022 and Google removed Less Secure Apps in September 2024 — both broke countless mailx and SMTP scripts overnight. An API-backed send survives those changes.
Add --track-opens when you want delivery signal on a code email, and --metadata to tag the send with a request ID for correlation in your logs. For a real product flow, a dedicated transactional sender still belongs behind your API — the CLI is the fastest path for scripts, internal tools, and test pipelines.
nylas email send --to user@example.com \
--subject "Your verification code" \
--body "Your code is $CODE." \
--track-opens --metadata request_id=ver_8841 --yesNext steps
- Test Email Flows with Playwright — Poll a real inbox from Playwright with expect.poll and nylas email…
- Extract OTP codes from email — the read side: pull a received code to your clipboard or a variable
- End-to-end email testing — wire send-and-verify into a Playwright or CI flow
- Password reset emails: choosing an API — latency and deliverability for code-driven account flows
- Getting started with Nylas CLI — connect your first account in under 5 minutes
- Command reference — every flag, subcommand, and example
- NIST SP 800-63B — the authenticator guidelines that classify email OTP