Most disposable email services are black boxes. You use the website, the emails appear, you have no idea what is running underneath and no way to customize anything.
FreeCustom.Email is different — there is an open-source project you can deploy as your own temp mail website, and a full API behind it that you can build on top of however you want. This post shows you exactly how to get your own instance running, how to hook into the API for custom functionality, and what you can build from there.
What You Are Actually Building
The open-source project gives you a complete, deployable temp mail frontend that connects to the FreeCustom.Email API. You get:
- A working temp mail website with your own branding and domain
- Full control over the UI — change anything you want
- The same underlying email infrastructure (real SMTP, real delivery, real OTP extraction)
- Access to the REST API for any custom features you want to add
You are not reinventing the email infrastructure. You are building a custom interface on top of infrastructure that already works.
Option 1: Use the Open-Source Frontend
FreeCustom.Email provides an open-source project you can clone and deploy. It is a complete temp mail UI that connects to the API.
The full guide with deployment instructions lives at freecustom.email/blog/build-your-own-temp-mail-website.
The basic flow:
# Clone the project
git clone https://github.com/DishIs/temp-mail
cd temp-mail
# Install dependencies
npm install
# Add your API key
cp .env.example .env.local
# Edit .env.local and set FCE_API_KEY=fce_your_key_here
Get your API key by running fce login (install the CLI first) or from the dashboard.
# Start dev server
npm run dev
You now have a running temp mail website at localhost:3000. Deploy it anywhere that runs Next.js — Vercel, Railway, Fly.io, your own VPS.
Option 2: Build From Scratch With the API
If you want more control, the REST API is straightforward. Here is a minimal temp mail app in about 60 lines of JavaScript:
// Simple temp mail app — no framework needed
const FCE_KEY = process.env.FCE_API_KEY;
const BASE = 'https://api2.freecustom.email/v1';
const headers = {
'Authorization': `Bearer ${FCE_KEY}`,
'Content-Type': 'application/json',
};
// 1. Create a random inbox
async function createInbox() {
const res = await fetch(`${BASE}/inboxes`, {
method: 'POST',
headers,
body: JSON.stringify({ inbox: `user-${Date.now()}@ditmail.info` }),
});
const { data } = await res.json();
return data.inbox;
}
// 2. List messages
async function getMessages(inbox) {
const res = await fetch(`${BASE}/inboxes/${inbox}/messages`, { headers });
const { data } = await res.json();
return data ?? [];
}
// 3. Get a single message
async function getMessage(inbox, id) {
const res = await fetch(`${BASE}/inboxes/${inbox}/messages/${id}`, { headers });
const { data } = await res.json();
return data;
}
// 4. Extract OTP (Growth plan+)
async function getOtp(inbox) {
const res = await fetch(`${BASE}/inboxes/${inbox}/otp`, { headers });
const { data } = await res.json();
return data?.otp;
}
// 5. Delete inbox when done
async function deleteInbox(inbox) {
await fetch(`${BASE}/inboxes/${inbox}`, { method: 'DELETE', headers });
}
That is the full API surface for a basic temp mail app. Five functions covering the whole lifecycle.
Adding Real-Time Email with WebSocket
Polling getMessages() works but feels slow. On Startup plan+, you can push emails to the browser the moment they arrive using the WebSocket endpoint:
// Client-side — connect to the real-time stream
function watchInbox(inbox, onEmail) {
const ws = new WebSocket(
`wss://api2.freecustom.email/v1/ws?inbox=${inbox}&api_key=${FCE_KEY}`
);
ws.onmessage = (event) => {
const email = JSON.parse(event.data);
onEmail(email);
};
ws.onclose = () => {
// Auto-reconnect after 2 seconds
setTimeout(() => watchInbox(inbox, onEmail), 2000);
};
return ws;
}
// Usage
const ws = watchInbox('user@ditmail.info', (email) => {
console.log('New email:', email.subject);
renderEmailInUI(email);
});
Emails appear in under 200ms. No polling loop, no refresh button, no delay.
A Minimal React Component
Here is a self-contained React component that gives you a working temp mail UI:
import { useState, useEffect, useCallback } from 'react';
const FCE_BASE = 'https://api2.freecustom.email/v1';
const headers = { 'Authorization': `Bearer ${process.env.NEXT_PUBLIC_FCE_KEY}` };
export function TempMailWidget() {
const [inbox, setInbox] = useState<string | null>(null);
const [messages, setMessages] = useState<any[]>([]);
const [selected, setSelected] = useState<any | null>(null);
const [loading, setLoading] = useState(false);
// Create inbox on mount
useEffect(() => {
const addr = `user-${Date.now()}@ditmail.info`;
fetch(`${FCE_BASE}/inboxes`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ inbox: addr }),
}).then(() => setInbox(addr));
}, []);
// Real-time WebSocket
useEffect(() => {
if (!inbox) return;
const ws = new WebSocket(
`wss://api2.freecustom.email/v1/ws?inbox=${inbox}&api_key=${process.env.NEXT_PUBLIC_FCE_KEY}`
);
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
setMessages(prev => [msg, ...prev]);
};
return () => ws.close();
}, [inbox]);
const openMessage = useCallback(async (id: string) => {
setLoading(true);
const res = await fetch(`${FCE_BASE}/inboxes/${inbox}/messages/${id}`, { headers });
const { data } = await res.json();
setSelected(data);
setLoading(false);
}, [inbox]);
if (!inbox) return <p>Creating inbox…</p>;
return (
<div className="temp-mail">
<div className="inbox-header">
<code>{inbox}</code>
<button onClick={() => navigator.clipboard.writeText(inbox)}>Copy</button>
</div>
{messages.length === 0 ? (
<p className="waiting">Waiting for emails…</p>
) : (
<ul className="message-list">
{messages.map(msg => (
<li key={msg.id} onClick={() => openMessage(msg.id)}>
<strong>{msg.from?.name ?? msg.from?.address}</strong>
<span>{msg.subject}</span>
</li>
))}
</ul>
)}
{selected && (
<div className="message-body">
<h3>{selected.subject}</h3>
<p className="from">From: {selected.from?.address}</p>
<div dangerouslySetInnerHTML={{ __html: selected.html ?? selected.text }} />
</div>
)}
</div>
);
}
Style it however you want. The core logic is about 60 lines.
Adding OTP Auto-Extraction to Your UI
This is the feature that users love most. When an email arrives that contains a verification code, surface it immediately:
async function checkForOtp(inbox: string): Promise<string | null> {
const res = await fetch(
`https://api2.freecustom.email/v1/inboxes/${inbox}/otp`,
{ headers }
);
const { success, data } = await res.json();
return success ? data?.otp ?? null : null;
}
// In your email display component
const otp = await checkForOtp(inbox);
if (otp) {
return (
<div className="otp-banner">
<span>Verification code:</span>
<strong>{otp}</strong>
<button onClick={() => navigator.clipboard.writeText(otp)}>Copy</button>
</div>
);
}
The API handles all OTP parsing — numeric codes, alphanumeric tokens, magic links. You just display whatever it returns. OTP extraction is available on Growth plan+.
CLI for Development and Testing
While building, the fce CLI is useful for quickly testing your inboxes without needing to use your UI:
# Install
curl -fsSL freecustom.email/install.sh | sh
fce login
# Watch any inbox in real time
fce watch user-1234567890@ditmail.info
# Check if OTP arrived
fce otp user-1234567890@ditmail.info
────────────────────────────────────────────────
OTP
────────────────────────────────────────────────
OTP · 212342
From · noreply@someservice.com
Subj · Your verification code
Time · 20:19:54
The CLI is MIT-licensed and open source: github.com/DishIs/fce-cli
What You Can Build on Top of This
Once you have the basic UI running, the API opens up a lot of directions:
Custom domain inboxes — on Growth plan, users can receive emails at user@yourdomain.com instead of the default FCE domains. Great for white-labelling.
Saved inboxes — let logged-in users register and keep specific addresses rather than getting a random one every session.
Notification webhooks — call your own endpoint when emails arrive by combining WebSocket with your backend.
Team inboxes — a shared inbox address multiple people on a team can watch, useful for staging environment alerts.
API access for power users — expose the FCE API to your own users with your own rate limits and billing, acting as a reseller layer.
The full-stack guide covers the monetization and multi-tenant patterns in detail if you want to go that route.
The Full API Reference
The complete API is documented at freecustom.email/api/docs and there is an interactive playground at freecustom.email/api/playground. The OpenAPI spec is at freecustom.email/openapi.yaml if you want to generate a client in another language.
The endpoints you will use most:
POST /v1/inboxes Create inbox
GET /v1/inboxes List inboxes
DELETE /v1/inboxes/{inbox} Remove inbox
GET /v1/inboxes/{inbox}/messages List messages
GET /v1/inboxes/{inbox}/messages/{id} Get message
GET /v1/inboxes/{inbox}/otp Extract OTP
WSS /v1/ws?inbox={inbox}&api_key={key} Real-time stream
GET /v1/domains Available domains
Auth is Authorization: Bearer fce_your_key on every request.
Pricing
The API is free to start — 5,000 requests per month with no credit card. Paid plans add higher limits, WebSocket delivery, and OTP extraction.
| Plan | Price | Req/month | WebSocket | OTP extraction |
|---|---|---|---|---|
| Free | $0 | 5,000 | ✗ | ✗ |
| Developer | $7/mo | 100,000 | ✗ | ✗ |
| Startup | $19/mo | 500,000 | ✓ | ✗ |
| Growth | $49/mo | 2,000,000 | ✓ | ✓ |
Full details: freecustom.email/api/pricing
Links
- 🌐 Open-source project guide: freecustom.email/blog/build-your-own-temp-mail-website
- 📖 API docs: freecustom.email/api/docs
- 🧪 API Playground: freecustom.email/api/playground
- 🖥️ CLI docs: freecustom.email/api/cli
- 📦 CLI GitHub: github.com/DishIs/fce-cli
- 🚀 CLI releases: github.com/DishIs/fce-cli/releases
- 💬 Discord: discord.com/invite/Ztp7kT2QBz
If you build something with this — a custom UI, a niche tool on top of the API, a white-labelled instance — I would genuinely like to see it. Drop a link in the comments.
Top comments (0)