Tools: I Built the First Official CLI for a Disposable Email Service — Here's Why and How to Use It

Tools: I Built the First Official CLI for a Disposable Email Service — Here's Why and How to Use It

The problem: email verification is the last manual step in automated pipelines

What is fce?

Install in one line

Login — browser-based, keychain-backed

fce dev — the command I use every single day

fce otp — no regex required

CI/CD — use FCE_API_KEY for headless environments

The full command surface

It also has a full REST API and official SDKs

Automation — AI agents, n8n, Make, Zapier

Pricing If you have ever tried to automate a signup flow in CI/CD, you know the pain. You can automate everything — provisioning, building, deploying, testing — but the moment your app sends a verification email, you are stuck. You either: None of those are good. So I built fce. fce is the official CLI for FreeCustom.Email — a disposable inbox API. It lets you create temporary inboxes, stream incoming emails in real time via WebSocket, and extract OTP codes automatically, all from your terminal. As far as I can tell, it is the only official CLI tool for any disposable or temporary email service in the world. Every other provider — Mailinator, Guerrilla Mail, Temp-Mail — stops at a REST API at best. No one else ships an installable binary. The source is fully open on GitHub: github.com/DishIs/fce-cli, MIT licensed, written in Go, available for macOS, Linux, and Windows. Or pick your package manager: Latest release is always at github.com/DishIs/fce-cli/releases. You can also update in-place at any time: Authentication opens your browser and saves a key to your OS keychain automatically. No manual API key copying, no environment variable setup for local use, no tokens expiring mid-test. Keys live in macOS Keychain, Windows Credential Manager, or Linux Secret Service (libsecret). They automatically reflect your current plan — upgrade your plan, the CLI picks it up instantly with no extra steps. This is the one that changed my workflow. fce dev combines inbox creation and real-time watching into a single command: Fresh disposable address, WebSocket connection open, emails arriving in real time — all in one command. When I am building a signup flow locally, I open one terminal pane with fce dev and trigger the flow in another. The email shows up in under 200ms. Before this existed, the equivalent was: open browser, go to a temp mail site, copy the address, paste it into the app, switch tabs, wait for the page to refresh, manually copy the OTP. That is six manual steps for something that should be zero steps. Once you have an inbox and an email has arrived, extracting the OTP is one command: In a script, capture just the code: The extraction engine handles numeric codes, alphanumeric tokens, magic links, and multi-part MIME emails. It has been tested across hundreds of different email service formats. If the email format changes, the extraction does not break — it is not regex-based. fce otp requires the Growth plan. fce watch (WebSocket streaming) requires Startup. All other commands work on the free tier. For CI runners where there is no browser, grab your API key from the FreeCustom.Email dashboard after logging in locally and set it as a secret: Fresh inbox per run, real OTP extraction, no shared state. Five parallel test jobs each get their own inbox with zero interference. Here is everything fce can do today: The CLI is the terminal face of FreeCustom.Email's API. If you prefer to work in code directly, there are official SDKs: JavaScript / TypeScript One thing I am particularly excited about: because fce is a proper CLI, it works with any AI agent that can run shell commands. With OpenClaw (or Claude, GPT-4o, etc.) you can just describe what you want: "Create a random inbox, watch it, and return the next OTP that arrives" The agent runs fce dev, watches the WebSocket output, calls fce otp, and returns the result. No glue code. For visual workflow automation, it works out of the box with n8n via Execute Command nodes. Native Make and Zapier integrations are coming in Q2 2026. Full automation docs: freecustom.email/api/automation The CLI works with every plan. The free tier is genuinely useful for local development: No credit card required for the free tier. Full pricing at freecustom.email/api/pricing. If you have ever lost time to the "wait for the verification email" step in a test suite, give fce a try. The free tier is zero commitment and fce dev alone is worth the two-minute install. Happy to answer questions in the comments — what email verification patterns are you dealing with in your projects? Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh # macOS / Linux — Homebrew -weight: 500;">brew tap DishIs/homebrew-tap -weight: 500;">brew -weight: 500;">install fce # Windows — Scoop scoop bucket add fce https://github.com/DishIs/scoop-bucket scoop -weight: 500;">install fce # Windows — Chocolatey choco -weight: 500;">install fce # All platforms — -weight: 500;">npm -weight: 500;">npm -weight: 500;">install -g fcemail@latest # All platforms — Go go -weight: 500;">install github.com/DishIs/fce-cli@latest # macOS / Linux — Homebrew -weight: 500;">brew tap DishIs/homebrew-tap -weight: 500;">brew -weight: 500;">install fce # Windows — Scoop scoop bucket add fce https://github.com/DishIs/scoop-bucket scoop -weight: 500;">install fce # Windows — Chocolatey choco -weight: 500;">install fce # All platforms — -weight: 500;">npm -weight: 500;">npm -weight: 500;">install -g fcemail@latest # All platforms — Go go -weight: 500;">install github.com/DishIs/fce-cli@latest # macOS / Linux — Homebrew -weight: 500;">brew tap DishIs/homebrew-tap -weight: 500;">brew -weight: 500;">install fce # Windows — Scoop scoop bucket add fce https://github.com/DishIs/scoop-bucket scoop -weight: 500;">install fce # Windows — Chocolatey choco -weight: 500;">install fce # All platforms — -weight: 500;">npm -weight: 500;">npm -weight: 500;">install -g fcemail@latest # All platforms — Go go -weight: 500;">install github.com/DishIs/fce-cli@latest [1/3] Opening browser… [2/3] Waiting for authentication… [3/3] Saving credentials… ✓ Logged in successfully! · Run `fce -weight: 500;">status` to see your account details. [1/3] Opening browser… [2/3] Waiting for authentication… [3/3] Saving credentials… ✓ Logged in successfully! · Run `fce -weight: 500;">status` to see your account details. [1/3] Opening browser… [2/3] Waiting for authentication… [3/3] Saving credentials… ✓ Logged in successfully! · Run `fce -weight: 500;">status` to see your account details. · Temporary inbox: dev-fy8x@ditcloud.info ✓ Watching for emails... ✓ Watching dev-fy8x@ditcloud.info GROWTH · Waiting for emails… (press Ctrl+C to -weight: 500;">stop) ──────────────────────────────────────────────────── ID JpW3DImT3 FROM "Dishant Singh" <[email protected]> SUBJ Your OTP for FCE: 212342 TIME 20:19:54 ──────────────────────────────────────────────────── · Temporary inbox: dev-fy8x@ditcloud.info ✓ Watching for emails... ✓ Watching dev-fy8x@ditcloud.info GROWTH · Waiting for emails… (press Ctrl+C to -weight: 500;">stop) ──────────────────────────────────────────────────── ID JpW3DImT3 FROM "Dishant Singh" <[email protected]> SUBJ Your OTP for FCE: 212342 TIME 20:19:54 ──────────────────────────────────────────────────── · Temporary inbox: dev-fy8x@ditcloud.info ✓ Watching for emails... ✓ Watching dev-fy8x@ditcloud.info GROWTH · Waiting for emails… (press Ctrl+C to -weight: 500;">stop) ──────────────────────────────────────────────────── ID JpW3DImT3 FROM "Dishant Singh" <[email protected]> SUBJ Your OTP for FCE: 212342 TIME 20:19:54 ──────────────────────────────────────────────────── fce otp dev-fy8x@ditcloud.info fce otp dev-fy8x@ditcloud.info fce otp dev-fy8x@ditcloud.info ──────────────────────────────────────────────── OTP ──────────────────────────────────────────────── OTP · 212342 From · "Dishant Singh" <[email protected]> Subj · Your OTP for FCE: 212342 Time · 20:19:54 ──────────────────────────────────────────────── OTP ──────────────────────────────────────────────── OTP · 212342 From · "Dishant Singh" <[email protected]> Subj · Your OTP for FCE: 212342 Time · 20:19:54 ──────────────────────────────────────────────── OTP ──────────────────────────────────────────────── OTP · 212342 From · "Dishant Singh" <[email protected]> Subj · Your OTP for FCE: 212342 Time · 20:19:54 OTP=$(fce otp dev-fy8x@ditcloud.info | grep "OTP ·" | awk '{print $NF}') echo "$OTP" # 212342 OTP=$(fce otp dev-fy8x@ditcloud.info | grep "OTP ·" | awk '{print $NF}') echo "$OTP" # 212342 OTP=$(fce otp dev-fy8x@ditcloud.info | grep "OTP ·" | awk '{print $NF}') echo "$OTP" # 212342 # .github/workflows/email-test.yml - name: E2E email verification env: FCE_API_KEY: ${{ secrets.FCE_API_KEY }} run: | -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh INBOX=$(fce inbox add random | tr -d '[:space:]') echo "Inbox: $INBOX" -weight: 500;">curl -s -X POST https://staging.myapp.com/api/signup \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\"}" OTP=$(fce otp "$INBOX" | grep "OTP ·" | awk '{print $NF}') echo "OTP: $OTP" -weight: 500;">curl -s -f -X POST https://staging.myapp.com/api/verify \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\", \"otp\": \"$OTP\"}" # .github/workflows/email-test.yml - name: E2E email verification env: FCE_API_KEY: ${{ secrets.FCE_API_KEY }} run: | -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh INBOX=$(fce inbox add random | tr -d '[:space:]') echo "Inbox: $INBOX" -weight: 500;">curl -s -X POST https://staging.myapp.com/api/signup \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\"}" OTP=$(fce otp "$INBOX" | grep "OTP ·" | awk '{print $NF}') echo "OTP: $OTP" -weight: 500;">curl -s -f -X POST https://staging.myapp.com/api/verify \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\", \"otp\": \"$OTP\"}" # .github/workflows/email-test.yml - name: E2E email verification env: FCE_API_KEY: ${{ secrets.FCE_API_KEY }} run: | -weight: 500;">curl -fsSL freecustom.email/-weight: 500;">install.sh | sh INBOX=$(fce inbox add random | tr -d '[:space:]') echo "Inbox: $INBOX" -weight: 500;">curl -s -X POST https://staging.myapp.com/api/signup \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\"}" OTP=$(fce otp "$INBOX" | grep "OTP ·" | awk '{print $NF}') echo "OTP: $OTP" -weight: 500;">curl -s -f -X POST https://staging.myapp.com/api/verify \ -H "Content-Type: application/json" \ -d "{\"email\": \"$INBOX\", \"otp\": \"$OTP\"}" -weight: 500;">npm -weight: 500;">install freecustom-email -weight: 500;">npm -weight: 500;">install freecustom-email -weight: 500;">npm -weight: 500;">install freecustom-email import { FreecustomEmailClient } from 'freecustom-email'; const client = new FreecustomEmailClient({ apiKey: process.env.FCE_API_KEY }); await client.inboxes.register('[email protected]'); const otp = await client.otp.waitFor('[email protected]'); console.log(otp); // '212342' import { FreecustomEmailClient } from 'freecustom-email'; const client = new FreecustomEmailClient({ apiKey: process.env.FCE_API_KEY }); await client.inboxes.register('[email protected]'); const otp = await client.otp.waitFor('[email protected]'); console.log(otp); // '212342' import { FreecustomEmailClient } from 'freecustom-email'; const client = new FreecustomEmailClient({ apiKey: process.env.FCE_API_KEY }); await client.inboxes.register('[email protected]'); const otp = await client.otp.waitFor('[email protected]'); console.log(otp); // '212342' -weight: 500;">pip -weight: 500;">install freecustom-email -weight: 500;">pip -weight: 500;">install freecustom-email -weight: 500;">pip -weight: 500;">install freecustom-email from freecustom_email import FreeCustomEmail import asyncio, os client = FreeCustomEmail(api_key=os.environ["FCE_API_KEY"]) async def main(): await client.inboxes.register("[email protected]") otp = await client.otp.wait_for("[email protected]") print(otp) # '212342' asyncio.run(main()) from freecustom_email import FreeCustomEmail import asyncio, os client = FreeCustomEmail(api_key=os.environ["FCE_API_KEY"]) async def main(): await client.inboxes.register("[email protected]") otp = await client.otp.wait_for("[email protected]") print(otp) # '212342' asyncio.run(main()) from freecustom_email import FreeCustomEmail import asyncio, os client = FreeCustomEmail(api_key=os.environ["FCE_API_KEY"]) async def main(): await client.inboxes.register("[email protected]") otp = await client.otp.wait_for("[email protected]") print(otp) # '212342' asyncio.run(main()) - Keep a shared test inbox that becomes a mess of race conditions when tests run in parallel - Mock the email step and quietly -weight: 500;">stop testing the actual delivery pipeline - Write fragile regex against a third-party API and break every time the email format changes - Just... click through it manually in staging - 🖥️ CLI overview and docs: freecustom.email/api/cli - 📦 GitHub repo: github.com/DishIs/fce-cli - 🚀 Latest release: github.com/DishIs/fce-cli/releases/latest - 🤖 Automation hub: freecustom.email/api/automation - 📖 API docs: freecustom.email/api/docs - 💬 Discord: discord.com/invite/Ztp7kT2QBz