<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ishan Shrestha</title>
    <description>The latest articles on DEV Community by Ishan Shrestha (@ishan_shrestha).</description>
    <link>https://dev.to/ishan_shrestha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4103034%2Fa58ed59a-0eea-4921-833d-4845927b94f9.png</url>
      <title>DEV Community: Ishan Shrestha</title>
      <link>https://dev.to/ishan_shrestha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ishan_shrestha"/>
    <language>en</language>
    <item>
      <title>Your disposable email list is rotting (size wont save you)</title>
      <dc:creator>Ishan Shrestha</dc:creator>
      <pubDate>Mon, 14 Sep 2026 15:02:51 +0000</pubDate>
      <link>https://dev.to/ishan_shrestha/your-disposable-email-list-is-rotting-size-wont-save-you-26a1</link>
      <guid>https://dev.to/ishan_shrestha/your-disposable-email-list-is-rotting-size-wont-save-you-26a1</guid>
      <description>&lt;p&gt;Most signup guides brag about list size.&lt;/p&gt;

&lt;p&gt;“110k domains.”&lt;/p&gt;

&lt;p&gt;“300k domains.”&lt;/p&gt;

&lt;p&gt;“Biggest blocklist on npm.”&lt;/p&gt;

&lt;p&gt;Cool screenshot. Doesn’t mean the gate still works on Thursday.&lt;/p&gt;

&lt;p&gt;Here’s the pattern I keep seeing. Someone copies a GitHub dump, wires disposable: true into validation, ships, and sleeps well. A week later a fresh yopmail clone walks straight through createUser. The list still looks huge. The product is already rotting.&lt;/p&gt;

&lt;p&gt;Size is a vanity metric. Freshness is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually breaks
&lt;/h2&gt;

&lt;p&gt;Day one feels great. Mailinator dies. Guerrilla Mail dies. The dashboard looks clean. You paste a package list into Laravel or Node and call it done.&lt;/p&gt;

&lt;p&gt;Then a burner provider spins up a cheap new domain. Or twenty. Your package hasn’t released in three months. The rule still “passes.” Trial seats fill with ghosts who never open the welcome mail. You start rewriting onboarding copy while the real leak is upstream.&lt;/p&gt;

&lt;p&gt;Binary blocklists have a second failure mode. They feel productive until you nuke a real person on Apple Hide My Email or SimpleLogin. Those addresses look weird. They are not tempmail. If every unfamiliar domain is guilty, you trade fake signups for angry real ones.&lt;/p&gt;

&lt;p&gt;You need both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A list that moves&lt;/li&gt;
&lt;li&gt;An allowlist for privacy relays on purpose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most tutorials ship a static file for #1 and skip #2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Size without motion is theater
&lt;/h2&gt;

&lt;p&gt;I run Email Score. Signup-gate check: syntax, DNS/MX, disposable, then allow or block. Our disposable domain database is 216,254 domains.&lt;/p&gt;

&lt;p&gt;I’m not leading with that number on purpose.&lt;/p&gt;

&lt;p&gt;Competitors already market bigger piles. TempMailChecker talks 300k+. A bigger integer doesnt mean their list moved this week. It means they scraped more history.&lt;/p&gt;

&lt;p&gt;The only number I care about after an Import is newly added. Everything else was already known.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we run instead
&lt;/h2&gt;

&lt;p&gt;Once a week we merge three maintainable, disposable-only feeds. Not free-provider lists. Not “every Gmail clone on earth.”&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;disposable-email-domains (CC0) — community standard, bindings everywhere, boring in a good way&lt;/li&gt;
&lt;li&gt;fakefilter (BSD-3) — closer to realtime provider monitoring&lt;/li&gt;
&lt;li&gt;groundcat (MIT) — aggregates then MX-validates, plus an allowlist worth respecting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normalize. Dedupe. Subtract privacy aliases hard: Apple Hide My Email, SimpleLogin, Firefox Relay, Duck aliases, addy.io.&lt;/p&gt;

&lt;p&gt;Also refuse to treat Gmail, Yahoo, Outlook, and the usual free providers as disposable. That confusion shows up in bad lists more than people admit.&lt;/p&gt;

&lt;p&gt;Then paste into the admin Import tab. One domain per line. Up to 50k per request. The DB skips what it already has.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quiet week, real numbers
&lt;/h2&gt;

&lt;p&gt;Last Import looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Public merge after allowlist: about 16.5k domains&lt;/li&gt;
&lt;li&gt;Already in our DB: most of them&lt;/li&gt;
&lt;li&gt;Newly added: 560&lt;/li&gt;
&lt;li&gt;Errors: 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The live disposable database is at 216,254 domains now.&lt;/p&gt;

&lt;p&gt;The story isn’t “we have 216k.”&lt;/p&gt;

&lt;p&gt;The story is 560 domains that would have been misses if wed frozen the list.&lt;/p&gt;

&lt;p&gt;If your weekly add count is zero for a month, either burners got polite (they didn’t) or your sources went stale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fumez60ryr9oj8i0t69r2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fumez60ryr9oj8i0t69r2.png" alt="Disposable Domains screenshot" width="720" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Operator checklist you can steal
&lt;/h2&gt;

&lt;p&gt;You don’t need our product to copy the shape.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sync on a schedule. Weekly is fine. Daily if trial abuse is loud.&lt;/li&gt;
&lt;li&gt;Prefer permissive disposable-only feeds. Dedupe. Subtract privacy relays on purpose.&lt;/li&gt;
&lt;li&gt;Hard-block known burners. Soft-score the gray area: brand-new domains, catch-all MX, role addresses like &lt;a href="mailto:info@"&gt;info@&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Fail open if the check times out. A dead validation path that takes signup down with it is worse than a delayed flag.&lt;/li&gt;
&lt;li&gt;Run the check before createUser. Cleaning the users table later is worse than never writing the junk.&lt;/li&gt;
&lt;li&gt;Keep confirmation email for ownership. Disposable detection is a courtesy filter, not proof of a human.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What we deliberately skip as the main gate: heavy SMTP RCPT probes. Slow. Often blocked. Catch-alls lie. Fine as an optional signal elsewhere. Bad as your only signup story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Email Score fits
&lt;/h2&gt;

&lt;p&gt;If you want the live piece without babysitting three GitHub remotes yourself, thats what we built.&lt;/p&gt;

&lt;p&gt;One API call. Syntax, DNS/MX, disposable. Signup-shaped verdict. Not a bulk list-cleaner. Not a 0–100 vanity score.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://emailscore.neuralevo.com/" rel="noopener noreferrer"&gt;Email Score · Validate emails before you send&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Validate syntax, MX, and deliverability before you send. Email validation API built by Neural Evo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://emailscore.neuralevo.com" rel="noopener noreferrer"&gt;https://emailscore.neuralevo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 216,254-domain database is evidence at the bottom, not the headline. The weekly merge is the habit. If your disposable list hasn’t moved since you pasted it in, it isn’t protecting you. Its decorating the README.&lt;/p&gt;

&lt;p&gt;If your list hasn’t moved in 30 days, what are you actually blocking?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally published on Medium: &lt;a href="https://medium.com/@ishanshrestha/your-disposable-email-list-is-rotting-size-wont-save-you-9edec7a9bfdc" rel="noopener noreferrer"&gt;https://medium.com/@ishanshrestha/your-disposable-email-list-is-rotting-size-wont-save-you-9edec7a9bfdc&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>saas</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I built a small C++ game engine so an AI IDE could touch the whole thing</title>
      <dc:creator>Ishan Shrestha</dc:creator>
      <pubDate>Thu, 03 Sep 2026 20:08:11 +0000</pubDate>
      <link>https://dev.to/ishan_shrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-3fki</link>
      <guid>https://dev.to/ishan_shrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-3fki</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://medium.com/@ishanshrestha/i-built-a-small-c-game-engine-so-an-ai-ide-could-touch-the-whole-thing-fee629c8fd78" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wanted to make a game. I also wanted the AI IDE on my desk to edit the whole running process, not just the scripts.&lt;/p&gt;

&lt;p&gt;Godot still makes you do linking and scene wiring in the UI. Unreal would not run on this laptop. Writing a raw Vulkan renderer from scratch meant months before I could drop a cube on screen. So I took the middle: Diligent Engine for the GPU, and I built everything else.&lt;/p&gt;

&lt;p&gt;The machine is an Intel HD 620. No discrete GPU. That forced the rest of the design. Keep draw calls low. Cull hard. Do not pull in heavy middleware.&lt;/p&gt;

&lt;p&gt;Demo: &lt;a href="https://youtu.be/nsptiy-I4Ps" rel="noopener noreferrer"&gt;https://youtu.be/nsptiy-I4Ps&lt;/a&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/Ishan5hrestha/SapanaEngine" rel="noopener noreferrer"&gt;https://github.com/Ishan5hrestha/SapanaEngine&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Diligent, not Godot or raw Vulkan
&lt;/h2&gt;

&lt;p&gt;Full engines hide the part I wanted to learn, and they are too fat for this hardware. Raw Vulkan is a career by itself. Diligent sits in between. Pipeline state, resource binding, HLSL once, targets Vulkan / D3D12 / Metal / D3D11 / GL. It is a dependency. It is not the codebase.&lt;/p&gt;

&lt;p&gt;I write ECS, scenes, assets, physics, cameras, input, and a flight sim. Diligent draws.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in the engine
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ECS and scenes.&lt;/strong&gt; EnTT. Scenes are JSON. Entities get transforms, mesh refs, physics blocks, LOD groups. A loader fills the registry at startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assets.&lt;/strong&gt; GLB/glTF through Diligent's loader, wrapped in my own cache. Builtin cube and plane for quick tests. String IDs like &lt;code&gt;builtin:cube&lt;/code&gt; or &lt;code&gt;meshes/drone.glb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rendering.&lt;/strong&gt; Two modes in config: Basic (forward, color, optional PCF shadows) and PBR (Diligent's GLTF PBR path, behind pimpl). Procedural sky, no skybox texture. Cascaded shadows. Frustum cull, distance LOD, far cull with hysteresis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Physics.&lt;/strong&gt; Jolt 5.3.0, FetchContent, pinned. Opt-in. No physics block in the JSON means mesh-only. Static and dynamic bodies, box and plane shapes for now. Public headers never see Jolt. Pimpl.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flight.&lt;/strong&gt; The sandbox has a quad. Two profiles on the same craft.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DJI: level, altitude hold, heading-frame move.&lt;/li&gt;
&lt;li&gt;FPV: acro, rate pitch/roll/yaw, idle throttle is freefall.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four virtual motor forces at the arm corners. Tunables in &lt;code&gt;config/flight.json&lt;/code&gt;. Cameras: freelook, chase, FPV nose. L flips the flight profile. K cycles cameras.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input.&lt;/strong&gt; Bindings live in JSON. Cursor capture for mouse look.&lt;/p&gt;

&lt;p&gt;Most of the C++ came out of the AI IDE. The real work was keeping it light enough that this laptop still runs, and fixing the parts the model got wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sandbox
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr75131c23cidlgfndcnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr75131c23cidlgfndcnl.png" alt="Sapana Sandbox — drone, trees, physics cubes on Vulkan" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That shot is Sapana Sandbox on Vulkan. Same frame you see in the title bar: mid-60s fps on integrated graphics. Green ground with static physics. Dynamic cubes. Visual-only glTF cube. One flyable drone. About forty static trees with box colliders.&lt;/p&gt;

&lt;p&gt;Edit a config or the scene JSON, rebuild, relaunch. No recompile hunt for every tweak. Builds on Linux (Mint 22.3 here) and Windows (&lt;code&gt;win&lt;/code&gt; branch).&lt;/p&gt;

&lt;h2&gt;
  
  
  The bug
&lt;/h2&gt;

&lt;p&gt;Far-distance cull, with LOD enabled, can strobe. Builtin cubes pop. Sky shows through. Freelook and drone share one view path, so both get it. Far hide vs camera far plane, shadow casters dropping while receivers still draw, PCF on basic meshes. Hysteresis helped. It is not fixed. Workaround: turn LOD off in &lt;code&gt;config/lod.json&lt;/code&gt; and restart.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is not
&lt;/h2&gt;

&lt;p&gt;It is not Unreal. It is not a product. It is a small engine for a specific game, on limited VRAM, where the whole loop is files an IDE can touch.&lt;/p&gt;

&lt;p&gt;If you want the boring details, the README in the repo has the layer list, controls, and build steps.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>gamedev</category>
      <category>graphics</category>
      <category>cpp</category>
    </item>
    <item>
      <title>How I Stop Fake Signups From Farming Free Credits (JS/Python)</title>
      <dc:creator>Ishan Shrestha</dc:creator>
      <pubDate>Mon, 31 Aug 2026 16:28:05 +0000</pubDate>
      <link>https://dev.to/ishan_shrestha/how-i-stop-fake-signups-from-farming-free-credits-jspython-10hd</link>
      <guid>https://dev.to/ishan_shrestha/how-i-stop-fake-signups-from-farming-free-credits-jspython-10hd</guid>
      <description>&lt;p&gt;A few client apps had the same leak.&lt;/p&gt;

&lt;p&gt;They offered free credits so people could try the product. Normal and fair. Then throwaway emails showed up, grabbed the free stuff, and disappeared. Support time went up. Costs went up. Real users got a worse experience.&lt;/p&gt;

&lt;p&gt;We tried free tools. One helped for a while. One broke at the worst time. After patching this more than once, I wanted one simple rule for signup:&lt;/p&gt;

&lt;p&gt;If the email looks abusive or undeliverable, block quietly and move on.&lt;/p&gt;

&lt;p&gt;That is what I built into: &lt;a href="https://emailscore.neuralevo.com/" rel="noopener noreferrer"&gt;https://emailscore.neuralevo.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is the practical version: what to check, and copy-paste code in JavaScript and Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule that matters
&lt;/h2&gt;

&lt;p&gt;Call the validate API and gate on &lt;code&gt;verdict&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;allow&lt;/code&gt;: continue signup / trial&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block&lt;/code&gt;: stop with a neutral message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can inspect other fields later. For signup abuse, start with &lt;code&gt;verdict&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST https://api.emailscore.neuralevo.com/api/v1/validate/email&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Header:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: Bearer YOUR_API_KEY&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript (Node fetch)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;shouldAllowSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.emailscore.neuralevo.com/api/v1/validate/email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Validate failed: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Primary signup gate&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verdict&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allow&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;shouldAllowSignup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ada@company.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_SCORE_API_KEY&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Show a neutral error. Do not explain the abuse logic.&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please use a different email.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Python (requests)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;should_allow_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.emailscore.neuralevo.com/api/v1/validate/email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verdict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;should_allow_signup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ada@company.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMAIL_SCORE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please use a different email.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What a response looks like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ada@company.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"normalized"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ada@company.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"verdict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"policyReason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"clean"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"syntax"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"miss"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deliverability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deliverable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mx_found"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful extras when you need them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;checks.disposable&lt;/code&gt;: throwaway / block list hit&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deliverability.status&lt;/code&gt;: can the domain receive mail&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;policyReason&lt;/code&gt;: why policy decided what it did&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most signup flows, still gate on &lt;code&gt;verdict&lt;/code&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this helps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Free trials and free credits&lt;/li&gt;
&lt;li&gt;Waitlists&lt;/li&gt;
&lt;li&gt;Invites&lt;/li&gt;
&lt;li&gt;Any form where fake emails quietly cost money&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you want to poke at it without wiring code first, there is a free checker on the homepage:&lt;br&gt;
&lt;a href="https://emailscore.neuralevo.com" rel="noopener noreferrer"&gt;https://emailscore.neuralevo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also free API access for devs.&lt;/p&gt;

&lt;p&gt;If you try the snippets, tell me what broke or felt unclear. I am still improveing this from more client pain, so blunt feedback helps more than polite compliments.&lt;/p&gt;




&lt;p&gt;Originally published on &lt;a href="https://medium.com/@ishanshrestha/how-i-stop-fake-signups-from-farming-free-credits-js-python-80f30d85334f" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>webdev</category>
      <category>api</category>
    </item>
  </channel>
</rss>
