agentsclimarketplace

Block disposable emails

Skill seangeng/skills/block-disposable-emails

Reject throwaway/disposable email addresses at signup by checking the domain against a maintained list, so spam accounts, trial-abuse, and fake signups drop sharply. Use this whenever the user is building or hardening a signup / registration / waitlist flow and mentions fake accounts, throwaway emails, mailinator / 10minutemail / temp-mail, trial abuse, bot signups, junk users, or wants to "improve signup quality" or "stop disposable emails." Reach for it when adding an auth/signup endpoint even if the user hasn't named disposable email yet — it's a cheap, high-leverage guard. Produces a server-side check (works on Node, edge runtimes like Cloudflare Workers, etc.) and the rules for layering it with a CAPTCHA and email verification.From its SKILL.md

Install
npx -y skills add seangeng/skills --skill block-disposable-emails

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • fetches URLsInstructs the agent to fetch 1 URL, including https://rawcdn.githack.com/disposable/disposable-email-domains/master/domains.json.

SKILL.md

3.4 KB, 665 tokens by cl100k_base, as published. Nobody here has run it

Block disposable emails at signup

If anyone can sign up with any email, a chunk of your "users" will be throwaway inboxes — mailinator.com, 10minutemail.com, and hundreds more. They're how people farm free trials, dodge bans, and pad the numbers with accounts that never convert. Checking the signup domain against a community-maintained list of disposable domains takes minutes and cuts a surprising amount of junk.

The check

Use the continuously-updated disposable/disposable-email-domains list (domains.json, tens of thousands of domains). Fetch it, cache for a day, load into a Set, and membership-test the domain after the @. A Set lookup is O(1); the daily cache means you're not hammering the CDN.

const LIST =
  "https://rawcdn.githack.com/disposable/disposable-email-domains/master/domains.json";

let cache: Set<string> | null = null;
let fetchedAt = 0;

async function disposableDomains() {
  if (cache && Date.now() - fetchedAt < 86_400_000) return cache; // 1 day
  const res = await fetch(LIST);
  cache = new Set<string>(await res.json());
  fetchedAt = Date.now();
  return cache;
}

export async function isDisposableEmail(email: string) {
  const domain = email.split("@")[1]?.toLowerCase().trim();
  if (!domain) return false;
  return (await disposableDomains()).has(domain);
}

Guard the signup handler:

if (await isDisposableEmail(email)) {
  return new Response("Please use a permanent email address.", { status: 422 });
}

Rules that make it actually work

  • Server-side only. The check belongs at the signup endpoint. A client-only check is trivially skipped — never trust it.
  • Cache correctly for the runtime. On an edge runtime like Cloudflare Workers, module-scope memory may not persist between requests; back the cache with KV (or similar) so you're not refetching the list constantly.
  • Use the maintained list, not a hand-rolled regex. A regex of domains you remember goes stale the day after you write it. The list doesn't.
  • Layer it — no single signal is enough. Stack cheap independent filters: a CAPTCHA (Cloudflare Turnstile / hCaptcha) stops bots before submit, the disposable-domain block stops throwaway humans, and a verification email at the end still requires a real, owned inbox. Each is minutes of work; together they compound.

From seangeng.com/writing/block-disposable-emails. Part of github.com/seangeng/skills. Credit: @venelinkochev.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.