Today I am introducing IronDome, the fastest and most accurate temporary email detector. I have been working on this for the last six months, and it took longer and was more complex than I anticipated in the beginning.
It all started on 13 May with another of my websites, an email marketing newsletter curator with a limited free AI feature that curated newsletters for users by chatting with them. I had rate-limited that feature because I incurred costs for the API usage. But on 13 May, the website saw an unusually large spike in new registrations, which I did not notice until the next morning.
What I saw was someone creating hundreds of accounts on the website every few hours. They were using the session cookie to send requests to the AI and had somehow managed to break the system prompt and use it for their own purposes. This was the first time I had faced anything like this, so I needed to find a solution. When I let my agent diagnose the issue, it found that most of the email addresses shared the same domain and came from a site called Emailnator.
I already had a limit on how many accounts an IP address could create. But the registrations were coming from different IPs, with each one staying below the limit. So the rate limit was working as configured, while the same person could keep getting a new allowance by creating another account.
That was the problem I wanted to solve with IronDome, a disposable email detection API. I wanted to check the email address before sending a verification email or giving the account any AI credits. And I wanted that check to be fast enough that someone signing up normally would not have to wait for it.
Finding a way to detect disposable emails
A temporary inbox can pass email verification, so I could still end up paying for AI usage and emails on throwaway accounts. I needed to check the address before granting access.
GitHub domain lists offered a fast local check, but I would have to keep updating them as disposable email services introduced new domains.
While researching this, I found something I had not known existed: websites offering temporary inboxes on Gmail, Yandex, Microsoft, and even iCloud. I could not block those providers' domains without rejecting genuine users. A domain-only list could not distinguish those inboxes from other addresses on the same provider, so I needed a way to check individual addresses. I will explain more in an upcoming blog about Oreman, IronDome's backbone. I also tested existing services; the published comparison records the gaps in that curated test.
Building the first version
I started with three goals:
- Fast: I wanted it to be faster than a human blink (which takes around 200 ms).
- Fresh: Keep discovering new disposable domains and addresses, and update the list quickly.
- Affordable and easy to integrate: Offer a focused disposable-email check without the cost or complexity of a full email-verification service.
I built the first prototype with three small Azure servers running Go in different regions, connected to a central Redis service (in hindsight, it seems stupid now). Redis helped track API usage and distribute new detection data. I also built a background process to discover new disposable entries.
The lookup itself was fast, but the request still had to travel to one of those servers. Checking the API quota could add another trip to Redis. If the application making the request was far from those regions, the network added time that a faster lookup could not remove.
One thing I tried was giving each server a small local allowance. Instead of asking Redis about every request, it could handle a number of checks before asking for more. This reduced the coordination, but the request still had to reach the server in the first place.
That was where I had to separate two things I was measuring. The server could handle a lot of requests per second, but an individual request could still take too long to return. For a signup check, the person waiting for that response matters more than the number of requests the server can handle.
I wanted the check to feel close to running a local list inside the application. Signup is where someone is trying to start using your product, and I did not want an email check to make that first interaction slow. So I started looking at moving the detector to an edge network.
Moving to an edge network
To keep response times low, I needed to run the detector close to the client server. So the next version used WebAssembly on Cloudflare Workers. The rationale was simple: Cloudflare has more than 348 points of presence (POPs) worldwide. But that also meant I had another problem to solve: fitting the detection data into the runtime without making it expensive to load every time an instance started.
I worked on storing the data more compactly while keeping the entries I needed to check. Simply removing entries would make it smaller, but it would also reduce coverage. The aim was to reduce what the runtime had to load without losing the addresses and domains the detector already knew about.
Over the next several months, I tested requests from different locations. Some of the routes I observed on Cloudflare added more latency than I wanted for this application. So I tested other edge platforms, including Fastly.
Fastly gave me more consistent results in those tests, and I chose it for the detector. By that point, I was looking at the complete request from the caller's side, including the network, rather than just measuring the lookup inside the service.
In the published latency tests, Node.js SDK medians ranged from 4.84 ms to 15.52 ms across four Google Cloud locations with reused HTTP connections. Those measurements depend on where the client runs and how it connects. I cannot promise that every request from every network will take less than 20 ms. The benchmark page also includes tail latency, fresh-connection results, and the methodology, so you can judge the numbers against your own application.
In my next blog, I will go into depth about the design decisions I made to make it faster, the tradeoffs, and how you can build a reliable, fast edge service on Fastly yourself.
The connection setup matters to those results, which is one reason I also wanted to provide SDKs. Developers should have a small, straightforward way to make the request and handle the response without rebuilding that code for every application. What happens after the check, such as asking for another address, stays under the application's control.
Keeping the detection data current
The speed and latency problem was solved, but the next problem was bigger. Making the API fast would not help if it kept missing the new addresses that led me to build it. Discovery needed to keep running alongside the detector.
I called that system Oreman. It is the backbone of IronDome. It looks for disposable email services, the domains they use, and the addresses they offer. Those discoveries feed into the detector's data, including individual addresses on shared providers where blocking the whole domain would reject genuine users. Oreman has taken the most time to build because disposable-email services keep changing; I’m still shipping improvements every day to keep up, and I’m seeing better detection as a result.
This is the ongoing work I wanted IronDome to handle for other developers. So far, it has discovered more than one million disposable email addresses. Keeping a local list is still an option, but it comes with the job of finding and distributing updates. I had started with a newsletter application, and maintaining disposable email data was not what I originally set out to spend my time on.
In a signup flow, I would put the IronDome check before sending verification or onboarding emails and before granting trial credits. The signup integration guide covers where to enforce the check and how to handle errors. If the address is identified as disposable, the application can ask for another one. Otherwise, it can continue with its normal verification. I would still keep rate limits and other abuse controls, because an email check cannot cover every way someone might misuse an application.
What I want to build next
This is the first version. I want to keep improving how Oreman discovers new disposable addresses and how quickly IronDome can check them. I also want to make it easier to add the check to the tools developers already use.
The API and SDKs are available today. The Apify Actor is live, and there is a Supabase signup hook. I am also working on Auth0, signup templates, and Zapier integration, with Klaviyo on the roadmap. These are at different stages, but the aim is the same: let a developer add the check without having to build the whole integration.
I started building IronDome because I needed it for my own application. I want another developer facing the same problem to be able to add a check and get back to working on their product.
If you are dealing with this too, give IronDome a try; it's free to try. The quickstart shows how to make your first check.
Special credits: code.storage and Auction Web (the eBay website from 1996). Many of the frontend components are inspired by both websites.
The IronDome team is me and my AI teammate, dot, powered by Codex and ChatGPT, seeing how far we can take this together.
Introducing IronDome
Product
Yogesh Pandar