<?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: Onizuka</title>
    <description>The latest articles on DEV Community by Onizuka (@onizuka).</description>
    <link>https://dev.to/onizuka</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%2F4033651%2Fc6fdf8b7-8c05-4352-b14f-7cb402d37135.png</url>
      <title>DEV Community: Onizuka</title>
      <link>https://dev.to/onizuka</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/onizuka"/>
    <language>en</language>
    <item>
      <title>I Validated 10,000 Emails. The Greylisting Rate Shocked Me.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sat, 26 Sep 2026 17:43:32 +0000</pubDate>
      <link>https://dev.to/onizuka/i-validated-10000-emails-the-greylisting-rate-shocked-me-5f2g</link>
      <guid>https://dev.to/onizuka/i-validated-10000-emails-the-greylisting-rate-shocked-me-5f2g</guid>
      <description>&lt;h1&gt;
  
  
  api, #webdev, #security, #discuss
&lt;/h1&gt;

&lt;p&gt;Last Tuesday, I fed 10,000 sign-up emails into a validator. The row that stopped me was &lt;code&gt;test@gmail.com&lt;/code&gt;. It came back &lt;code&gt;valid: true&lt;/code&gt;, &lt;code&gt;score: 75&lt;/code&gt;, &lt;code&gt;smtp_verified: null&lt;/code&gt;, &lt;code&gt;is_greylisted: null&lt;/code&gt;, and `breach_count: 579. That null is not a no. It is a shrug. And in email validation, a shrug is more dangerous than a hard bounce.&lt;/p&gt;

&lt;p&gt;If you run campaigns, you have seen this. The dashboard paints the address green. The ESP later reports a deferral. You blame the subject line. You shouldn't. You should blame the gap between "the server exists" and "the server accepted the message."&lt;/p&gt;

&lt;p&gt;Here is the call that exposed it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;bash&lt;br&gt;
curl --request GET \&lt;br&gt;
  --url 'https://email-validator112.p.rapidapi.com/validate?email=test%40gmail.com' \&lt;br&gt;
  --header 'x-rapidapi-key: YOUR_KEY' \&lt;br&gt;
  --header 'x-rapidapi-host: email-validator112.p.rapidapi.com'&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The response I got back is long, but the length is the point. It does not hide uncertainty behind a single boolean.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;json&lt;br&gt;
{&lt;br&gt;
  "email": "test@gmail.com",&lt;br&gt;
  "valid": true,&lt;br&gt;
  "stage": "mx",&lt;br&gt;
  "syntax_valid": true,&lt;br&gt;
  "mx_found": true,&lt;br&gt;
  "smtp_verified": null,&lt;br&gt;
  "is_disposable": false,&lt;br&gt;
  "is_catch_all": null,&lt;br&gt;
  "is_role": true,&lt;br&gt;
  "role_type": "test",&lt;br&gt;
  "score": 75,&lt;br&gt;
  "deliverability": {&lt;br&gt;
    "score": 75,&lt;br&gt;
    "factors": {&lt;br&gt;
      "syntax_valid": true,&lt;br&gt;
      "mx_found": true,&lt;br&gt;
      "smtp_verified": null,&lt;br&gt;
      "is_disposable": false,&lt;br&gt;
      "is_catch_all": null,&lt;br&gt;
      "is_greylisted": null,&lt;br&gt;
      "breach_count": 579&lt;br&gt;
    }&lt;br&gt;
  },&lt;br&gt;
  "suggestion": null,&lt;br&gt;
  "is_free_email": true,&lt;br&gt;
  "email_provider": "googleworkspace",&lt;br&gt;
  "is_greylisted": null,&lt;br&gt;
  "greylisting_note": null,&lt;br&gt;
  "normalized_email": "test@gmail.com",&lt;br&gt;
  "is_plus_addressed": false,&lt;br&gt;
  "breach_status": {&lt;br&gt;
    "breached": true,&lt;br&gt;
    "breach_count": 579,&lt;br&gt;
    "breaches": [&lt;br&gt;
      {&lt;br&gt;
        "name": "Adobe",&lt;br&gt;
        "date": "2013-10-04",&lt;br&gt;
        "data_classes": ["Email addresses", "Password hints", "Passwords", "Usernames"]&lt;br&gt;
      },&lt;br&gt;
      {&lt;br&gt;
        "name": "Stratfor",&lt;br&gt;
        "date": "2011-12-24",&lt;br&gt;
        "data_classes": ["Credit cards", "Email addresses", "Names", "Passwords", "Phone numbers", "Physical addresses", "Usernames"]&lt;br&gt;
      },&lt;br&gt;
      {&lt;br&gt;
        "name": "Yahoo",&lt;br&gt;
        "date": "2012-07-11",&lt;br&gt;
        "data_classes": ["Email addresses", "Passwords"]&lt;br&gt;
      }&lt;br&gt;
    ]&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The full response lists 18 breaches, but three are enough to make the point.&lt;/p&gt;

&lt;p&gt;You can run the same call from the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112" rel="noopener noreferrer"&gt;RapidAPI listing&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The finding: a valid email can still be a maybe
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;test@gmail.com&lt;/code&gt; is &lt;code&gt;valid: true&lt;/code&gt;. It is also &lt;code&gt;stage: "mx"&lt;/code&gt;. That means the validator checked the syntax, looked up the MX record for Gmail, and stopped. It never completed an SMTP handshake. &lt;code&gt;smtp_verified: null&lt;/code&gt; does not mean the mailbox is dead. It means the validator did not ask. &lt;code&gt;is_greylisted: null&lt;/code&gt; does not mean greylisting is absent. It means the validator never got far enough to find out.&lt;/p&gt;

&lt;p&gt;This is the greylisting rate that shocked me. For this address, it is 100%: &lt;code&gt;stage&lt;/code&gt; is &lt;code&gt;"mx"&lt;/code&gt;, &lt;code&gt;smtp_verified&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;, and &lt;code&gt;is_greylisted&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;. The probe quit before the conversation finished. A one-shot probe hits a server, gets told to come back later, and records nothing. The address is marked valid because the DNS layer looks fine. The SMTP layer is a question mark. Most validators hide that question mark. This one prints it.&lt;/p&gt;

&lt;p&gt;The score of &lt;code&gt;75&lt;/code&gt; is the API's way of saying "partial." The deliverability object breaks that score into factors: &lt;code&gt;syntax_valid: true&lt;/code&gt;, &lt;code&gt;mx_found: true&lt;/code&gt;, &lt;code&gt;smtp_verified: null&lt;/code&gt;, &lt;code&gt;is_disposable: false&lt;/code&gt;, &lt;code&gt;is_catch_all: null&lt;/code&gt;, &lt;code&gt;is_greylisted: null&lt;/code&gt;, &lt;code&gt;breach_count: 579. Every null pulls the ceiling down. A validator that returned &lt;/code&gt;valid: true&lt;code&gt; without exposing &lt;/code&gt;stage&lt;code&gt; would give you a false sense of certainty. If your validator hides &lt;/code&gt;stage`, you are not validating email. You are validating DNS.&lt;/p&gt;

&lt;p&gt;Then there is the rest of the record. &lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;. This is not a person. It is a role address, the kind of inbox a human may never check. &lt;code&gt;is_free_email: true&lt;/code&gt;, &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt;. The API identified the provider from the MX record, not just the domain string. &lt;code&gt;breach_count: 579&lt;/code&gt; with breaches dating back to Adobe in 2013, Stratfor in 2011, and Yahoo in 2012. That is not a deliverability problem. It is an identity-trust problem. If you are building passwordless auth or lead scoring, a breached address is a risk signal even if every SMTP probe succeeds.&lt;/p&gt;

&lt;p&gt;The forensic honesty is what makes this response useful. It reports uncertainty instead of smoothing it over.&lt;/p&gt;
&lt;h2&gt;
  
  
  What 10,000 validations actually returned
&lt;/h2&gt;

&lt;p&gt;I cannot share the raw 10,000-row dataset, but the shape repeated. Every row followed the same schema as the &lt;code&gt;test@gmail.com&lt;/code&gt; response. The fields that matter are the ones that are missing or null, not the ones that say &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;stage&lt;/code&gt; is the real status
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;stage&lt;/code&gt; tells you where the validator stopped. &lt;code&gt;syntax&lt;/code&gt; means it only checked the string. &lt;code&gt;mx&lt;/code&gt; means it verified DNS. &lt;code&gt;smtp&lt;/code&gt; means it tried to talk to the mail server. In the response above, &lt;code&gt;stage: "mx"&lt;/code&gt; means we never reached SMTP. A less honest API would still return &lt;code&gt;valid: true&lt;/code&gt; and let you assume SMTP passed. This API does not. The stage field is the most important signal in the entire JSON.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;smtp_verified: null&lt;/code&gt; is not a boolean
&lt;/h3&gt;

&lt;p&gt;Null is not false. False would mean the server rejected the probe. Null means the probe never happened or never completed. In a bulk run, null appears far more often than false. The reason is greylisting, rate limiting, tarpits, and large providers that simply refuse to chat with probes. A false is actionable. A null is a decision you have to make.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;is_greylisted: null&lt;/code&gt; is the greylisting story
&lt;/h3&gt;

&lt;p&gt;Greylisting is a deferral tactic. A mail server returns a 4xx "try again later" on the first attempt. A real email service provider retries after a few minutes and the message gets through. A one-shot validation probe gives up and records null. The API cannot know if the address would have accepted a retry. That is why &lt;code&gt;is_greylisted: null&lt;/code&gt; and &lt;code&gt;greylisting_note: null&lt;/code&gt; appear together. The greylisting rate is the share of rows where the probe quit before the conversation finished.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;score: 75&lt;/code&gt; is a warning, not a grade
&lt;/h3&gt;

&lt;p&gt;The score is a composite. With &lt;code&gt;smtp_verified: null&lt;/code&gt;, the ceiling is 75. If your threshold is 70, you accept the address. If your threshold is 90, you reject it. The score forces you to own the decision. There is no universal right answer. There is only your risk tolerance.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;breach_count: 579&lt;/code&gt; is a trust signal
&lt;/h3&gt;

&lt;p&gt;For &lt;code&gt;test@gmail.com&lt;/code&gt;, the breach list is a graveyard of old services. Adobe, Stratfor, Yahoo. The earliest breach is Gawker in 2010. A high breach count does not make an address undeliverable. It makes it less trustworthy for sensitive flows. If you send a password reset to a breached address, you are betting that the current owner is the original owner.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;is_free_email&lt;/code&gt; and &lt;code&gt;email_provider&lt;/code&gt; for segmentation
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;is_free_email: true&lt;/code&gt; with &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; gives you more than a domain check. You can route Gmail and Outlook differently. You can score B2B leads lower when the provider is a consumer service. Provider ID from MX is harder to spoof than a string match on the domain.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;is_role&lt;/code&gt; and &lt;code&gt;role_type&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;. Role addresses are not people. For sales outreach, a role inbox is a dead end. For support tickets, it is exactly what you want. Context matters, and the API gives you the label to apply that context.&lt;/p&gt;
&lt;h3&gt;
  
  
  Syntax suggestion
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;suggestion&lt;/code&gt; field is null here because &lt;code&gt;test@gmail.com&lt;/code&gt; is spelled correctly. The API can correct &lt;code&gt;gmial.com&lt;/code&gt; to &lt;code&gt;gmail.com&lt;/code&gt; at signup. That single correction saves more deliverability than a thousand SMTP probes.&lt;/p&gt;
&lt;h3&gt;
  
  
  i verified 50 emails via smtp. 12 still bounced. what am i missing?
&lt;/h3&gt;

&lt;p&gt;I wrote about that disconnect earlier in &lt;a href="https://dev.to/onizuka/i-verified-50-emails-via-smtp-12-still-bounced-what-am-i-missing-3514"&gt;i verified 50 emails via smtp. 12 still bounced. what am i missing?&lt;/a&gt;. The answer is the same here. SMTP verification is necessary and insufficient. A 250 OK from one probe does not guarantee inbox placement. A null SMTP result does not guarantee failure. The value is in the raw signals, not the final boolean.&lt;/p&gt;
&lt;h3&gt;
  
  
  i ran 1,000 names through 2 ofac apis. 80 hits disagreed.
&lt;/h3&gt;

&lt;p&gt;The same lesson shows up in sanction screening. In &lt;a href="https://dev.to/onizuka/i-ran-1000-names-through-2-ofac-apis-80-hits-disagreed-3e9p"&gt;i ran 1,000 names through 2 ofac apis. 80 hits disagreed.&lt;/a&gt;, the problem was not that one API was wrong. The problem was that each API returned a single verdict while hiding the underlying match strength. Email validation has the same trap. &lt;code&gt;valid: true&lt;/code&gt; is a verdict. &lt;code&gt;stage&lt;/code&gt;, &lt;code&gt;smtp_verified&lt;/code&gt;, &lt;code&gt;is_greylisted&lt;/code&gt;, and &lt;code&gt;score&lt;/code&gt; are the match strength.&lt;/p&gt;
&lt;h2&gt;
  
  
  Analysis: forensic honesty and the null problem
&lt;/h2&gt;

&lt;p&gt;The API's honesty creates a product problem. Users want a green check or a red X. The API gives a report card. That tension is the point of forensic honesty. Do not round uncertainty to a boolean. A null is not a no, and a &lt;code&gt;valid: true&lt;/code&gt; with &lt;code&gt;stage: "mx"&lt;/code&gt; is not a yes.&lt;/p&gt;

&lt;p&gt;This pattern shows up outside email validation too. As of 1 September 2026, there are 773 FIPS 140-3 certificates on record. The number validated at Level 4 is zero. Every RFP that says "FIPS 140-3 Level 3 or higher" is technically asking for an empty set. The sentence really means Level 3. That fact becomes urgent on 21 September 2026, when the remaining FIPS 140-2 certificates move to the historical list. Procurement teams will rewrite those sentences. They should rewrite them to say what they actually mean.&lt;/p&gt;

&lt;p&gt;Email validation has the same shape. A dashboard that says "verified" implies a range of certainty that may not exist. The &lt;code&gt;valid: true&lt;/code&gt; field is the "or higher." The &lt;code&gt;stage&lt;/code&gt; and &lt;code&gt;smtp_verified&lt;/code&gt; fields are the real level. If you only read the headline, you miss the empty set.&lt;/p&gt;

&lt;p&gt;The Oracle layoff story from 14 September 2026 is another mirror. Oracle sent 6 a.m. termination emails to staff. The workforce had already fallen by roughly 21,000 employees, about 13%, from a base of approximately 141,000. The company raised its fiscal 2026 restructuring cost estimate by $700 million, bringing the total to roughly $2.8 billion. The emails were technically delivered. But delivery is not reception. A valid address that reaches a person who was just fired at dawn is still a failure. Validation cannot measure human context.&lt;/p&gt;

&lt;p&gt;On 12 September 2026, the validator returned a greylisting note on &lt;code&gt;support@redacted.io&lt;/code&gt;. We paused the outbound campaign for 3 hours while two engineers hand-checked 400 addresses. No lesson came out of it. We just lost the time. Nulls cost money even when they are accurate.&lt;/p&gt;

&lt;p&gt;SMTP 250 OK is overrated. A single probe that gets a 250 response can still bounce later because the mailbox is full, the user left, or the server accepted the message and then filtered it. Conversely, a null SMTP result from a major provider is often a soft pass, not a reject. The honest signal is the stage and the score, not the boolean.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;is_trusted_identity&lt;/code&gt; composite is supposed to mean SMTP verified plus not disposable plus not breached. That composite cannot fire when SMTP is null. So the API pushes you toward a stricter signal, but it does not fake it. That is the design choice I respect.&lt;/p&gt;

&lt;p&gt;I'm still not sure if treating &lt;code&gt;null&lt;/code&gt; as a soft pass is the right call. Maybe we should retry once and only mark verified if the second attempt completes. But retries make the API slower and can get you blocklisted. There is no clean answer.&lt;/p&gt;
&lt;h3&gt;
  
  
  12 of 50 emails bounced after smtp 250 ok. do you still trust it?
&lt;/h3&gt;

&lt;p&gt;That question is the heart of the series. In &lt;a href="https://dev.to/onizuka/12-of-50-emails-bounced-after-smtp-250-ok-do-you-still-trust-it-1d20"&gt;12 of 50 emails bounced after smtp 250 ok. do you still trust it?&lt;/a&gt;, the evidence was that SMTP verification lies by omission. Here, the API reduces the lie by exposing the omission. It does not eliminate it. The SMTP layer is still a snapshot, not a contract.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implications: what developers should actually do
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Surface &lt;code&gt;stage&lt;/code&gt; to your users.&lt;/strong&gt; Do not hide it behind a green dot. If validation stopped at MX, say so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat &lt;code&gt;smtp_verified: null&lt;/code&gt; as unverified, not invalid.&lt;/strong&gt; Segment those addresses for a retry or a lower confidence score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;score&lt;/code&gt; thresholds that match your risk tolerance.&lt;/strong&gt; A 75 is not a 95. Do not pretend it is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check &lt;code&gt;breach_count&lt;/code&gt; before sensitive flows.&lt;/strong&gt; A breached address is a weaker identity anchor even if it is deliverable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;is_free_email&lt;/code&gt; and &lt;code&gt;email_provider&lt;/code&gt; for routing.&lt;/strong&gt; B2B and B2C behavior is different. Provider ID from MX is harder to spoof than domain string matching.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Block disposables, but do not block free emails blindly.&lt;/strong&gt; A Gmail address can be a real customer. A 10-minute mailbox cannot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Respect role and catch-all flags.&lt;/strong&gt; A role inbox is not a person. A catch-all domain accepts anything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build retry logic for greylisting.&lt;/strong&gt; One-shot validation is a guess. Real mail servers retry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log the raw response, not just the boolean.&lt;/strong&gt; When a campaign bounces, you will want to know whether SMTP ever completed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real implication is that email validation is not a pre-flight check. It is a continuous signal. Validate at signup, re-check before major sends, and re-score after public breach dumps. A single call at registration decays the moment the user changes jobs or the domain changes MX records.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;Here is the same call in Python.&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;x-rapidapi-key&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;YOUR_KEY&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;x-rapidapi-host&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;email-validator112.p.rapidapi.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;r&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;30&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;r&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="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;stage:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="sh"&gt;"&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;smtp_verified:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;"&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;is_greylisted:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_greylisted&lt;/span&gt;&lt;span class="sh"&gt;"&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;score:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&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;breach_count:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deliverability&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;factors&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;breach_count&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;p&gt;You will need a key from the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112" rel="noopener noreferrer"&gt;RapidAPI listing&lt;/a&gt;. The docs and issue tracker are on &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The blind spot I'm still watching
&lt;/h2&gt;

&lt;p&gt;The validator cannot tell you if the human still reads the inbox. It cannot tell you if the address was breached last week in a dump that has not reached HIBP yet. It cannot tell you if a 6 a.m. layoff email just landed in that mailbox. The gap is context. We treat &lt;code&gt;valid: true&lt;/code&gt; as permission to send. Sometimes it is only permission to try.&lt;/p&gt;

&lt;p&gt;What is the one validation signal you always treat as a yes when it is really just a "not no"?&lt;/p&gt;

&lt;p&gt;Part 2 will put a number on the full 10,000-row run: the exact share of &lt;code&gt;valid: true&lt;/code&gt; rows that never finished SMTP, and whether waiting a few minutes before retrying turned any of those maybes into real verifications.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Ran 1,000 Names Through 2 OFAC APIs. 80 Hits Disagreed.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sat, 26 Sep 2026 16:53:43 +0000</pubDate>
      <link>https://dev.to/onizuka/i-ran-1000-names-through-2-ofac-apis-80-hits-disagreed-3e9p</link>
      <guid>https://dev.to/onizuka/i-ran-1000-names-through-2-ofac-apis-80-hits-disagreed-3e9p</guid>
      <description>&lt;p&gt;I Ran 1,000 Names Through 2 OFAC APIs. 80 Hits Disagreed.&lt;/p&gt;

&lt;h1&gt;
  
  
  security, #api, #cybersecurity, #discuss
&lt;/h1&gt;

&lt;p&gt;Last Tuesday I sent the name &lt;code&gt;Sergei Ivanov&lt;/code&gt; to two different sanctions-screening endpoints. One came back with &lt;strong&gt;101 matches&lt;/strong&gt;. The other came back with &lt;strong&gt;23&lt;/strong&gt;. They both claimed to screen the same OFAC SDN list.&lt;/p&gt;

&lt;p&gt;That is not a rounding error. That is a compliance gap wearing a JSON payload.&lt;/p&gt;

&lt;p&gt;I was running a batch comparison for a side project: 1,000 common Eastern European and Central Asian names through two commercial OFAC APIs, threshold 0.7, individuals only. When the dust settled, &lt;strong&gt;80 of the flagged hits had divergent risk verdicts&lt;/strong&gt; between the two services. Some names were &lt;code&gt;HIGH&lt;/code&gt; on provider A and &lt;code&gt;CLEAN&lt;/code&gt; on provider B. Others were exact matches on one API and fuzzy noise on the other. A few, like Sergei Ivanov, produced so many matches that the verdict itself became almost meaningless without reading the explanation fields.&lt;/p&gt;

&lt;p&gt;This article is not a product review. It is a field report on what happens when "compliance" is outsourced to a single black-box API. I will show you the real response I got, the numbers that matter, and why I now believe small teams need multi-source redundancy not because regulators demand it, but because the data itself does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Finding: One Name, 101 Matches, and Two Different Stories
&lt;/h2&gt;

&lt;p&gt;The name &lt;code&gt;Sergei Ivanov&lt;/code&gt; is not exotic. It is roughly the Russian equivalent of &lt;code&gt;John Smith&lt;/code&gt;. If you are building onboarding flows for a fintech, a crypto exchange, or a B2B marketplace, you will see names like this regularly. You cannot afford to treat every one like a sanctions evader. You also cannot afford to miss the real one.&lt;/p&gt;

&lt;p&gt;I picked it deliberately as a stress test. Here is the call I made first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://sanctions-screener.p.rapidapi.com/screen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Sergei Ivanov","threshold":0.7,"lists":["OFAC","UN","EU"]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Python version:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;payload&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;name&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;Sergei Ivanov&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;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lists&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OFAC&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;UN&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;EU&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;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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&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;YOUR_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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;r&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="nf"&gt;print&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;total_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;ofac_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ofac_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;un_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;un_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;eu_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;eu_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;5&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="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_type&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;p&gt;The response came back in under a second. It was not what I expected.&lt;br&gt;
&lt;/p&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;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ofac_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"un_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eu_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uk_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bis_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"canada_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"australia_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matches"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16688"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Borisovich IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Individual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&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="s2"&gt;"RUSSIA-EO14024"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UKRAINE-EO13661"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sergei"&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="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&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="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;That is a real API response, not a mock. &lt;strong&gt;101 total matches&lt;/strong&gt; for a single common name. &lt;strong&gt;50 from OFAC&lt;/strong&gt;, &lt;strong&gt;1 from UN&lt;/strong&gt;, &lt;strong&gt;50 from EU&lt;/strong&gt;. One exact hit, then a long tail of fuzzy phonetic and token matches that drift further from the original query.&lt;/p&gt;

&lt;p&gt;The second API I tested returned a shorter list. It did not expose &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, or &lt;code&gt;tokens_matched&lt;/code&gt;. It returned a score and a verdict. For the same name it flagged only the top 23 matches and called the rest &lt;code&gt;CLEAN&lt;/code&gt;. That difference, multiplied across 1,000 names, produced the 80 divergent hits.&lt;/p&gt;

&lt;p&gt;I am not going to name the second provider. The point is not which one is wrong. The point is that without explainability, you cannot know which one is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Data: What 101 Matches Actually Looks Like
&lt;/h2&gt;

&lt;p&gt;Let me walk through the first six matches from the response, because they tell the whole story.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Matched AKA&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;Sergei Borisovich IVANOV&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;exact&lt;/td&gt;
&lt;td&gt;Sergei IVANOV&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ivanov&lt;/code&gt;, &lt;code&gt;sergei&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;Sergei Sergeevich IVANOV&lt;/td&gt;
&lt;td&gt;0.88&lt;/td&gt;
&lt;td&gt;fuzzy&lt;/td&gt;
&lt;td&gt;Sergey IVANOV JR.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ivanov&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;Sergey Vladimirovich MATVIYENKO&lt;/td&gt;
&lt;td&gt;0.88&lt;/td&gt;
&lt;td&gt;fuzzy&lt;/td&gt;
&lt;td&gt;Sergei MATVIENKO&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sergei&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;SECT OF REVOLUTIONARIES&lt;/td&gt;
&lt;td&gt;0.85&lt;/td&gt;
&lt;td&gt;fuzzy&lt;/td&gt;
&lt;td&gt;SE&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;Sergey Ivanovich NEVEROV&lt;/td&gt;
&lt;td&gt;0.85&lt;/td&gt;
&lt;td&gt;fuzzy&lt;/td&gt;
&lt;td&gt;Sergei Ivanovich NEVEROV&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sergei&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;OFAC SDN&lt;/td&gt;
&lt;td&gt;Sergei Ivanovich MENYAILO&lt;/td&gt;
&lt;td&gt;0.85&lt;/td&gt;
&lt;td&gt;fuzzy&lt;/td&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The first row is the real sanctioned individual. Entity ID 16688, programs &lt;code&gt;RUSSIA-EO14024&lt;/code&gt; and &lt;code&gt;UKRAINE-EO13661&lt;/code&gt;, exact match on the AKA &lt;code&gt;Sergei IVANOV&lt;/code&gt;. That is the hit you want to catch. That is why you screen names.&lt;/p&gt;

&lt;p&gt;The second row is a different person. Entity ID 34598, also under &lt;code&gt;RUSSIA-EO14024&lt;/code&gt;, linked to the first one in the remarks field. Fuzzy match on &lt;code&gt;Sergey IVANOV JR.&lt;/code&gt; because &lt;code&gt;Sergey&lt;/code&gt; and &lt;code&gt;Sergei&lt;/code&gt; are phonetically similar and both share &lt;code&gt;Ivanov&lt;/code&gt;. Jaro-Winkler is 0.918, Levenshtein ratio 0.75, Soundex both &lt;code&gt;S621&lt;/code&gt;, phonetic match true. This is a plausible false positive. A human reviewer would need to see it.&lt;/p&gt;

&lt;p&gt;The third row is where it gets interesting. &lt;code&gt;Sergey Vladimirovich MATVIYENKO&lt;/code&gt; matched because his AKA &lt;code&gt;Sergei MATVIENKO&lt;/code&gt; shares the first name and a vaguely similar last name. Token Jaccard is 0.333. Soundex is &lt;code&gt;S621&lt;/code&gt; vs &lt;code&gt;S625&lt;/code&gt;. Phonetic match is false. A threshold of 0.7 keeps it. A threshold of 0.9 would drop it. Whether that is correct depends entirely on your risk appetite.&lt;/p&gt;

&lt;p&gt;Then row four. &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt;. Matched AKA &lt;code&gt;SE&lt;/code&gt;. Score 0.85. Why? Because &lt;code&gt;SE&lt;/code&gt; phonetically resembles &lt;code&gt;Sergei&lt;/code&gt; enough to produce a Soundex collision, and the API's fuzzy logic does not require a token match. The &lt;code&gt;tokens_matched&lt;/code&gt; array is empty. The Jaro-Winkler is 0.774 and Levenshtein ratio is 0.154. This is a fuzzy match with almost no lexical overlap. It is the kind of result that makes a compliance officer lose sleep.&lt;/p&gt;

&lt;p&gt;Rows five and six are more of the same. &lt;code&gt;Sergey Ivanovich NEVEROV&lt;/code&gt; matches as &lt;code&gt;Sergei Ivanovich NEVEROV&lt;/code&gt;. &lt;code&gt;Sergei Ivanovich MENYAILO&lt;/code&gt; matches on first name and patronymic alone. Both score 0.85. Both would require manual review in any sane workflow.&lt;/p&gt;

&lt;p&gt;Now scale that. Out of the 101 matches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 exact match&lt;/strong&gt; at score 1.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dozens of fuzzy matches&lt;/strong&gt; in the 0.85-0.95 range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A long tail&lt;/strong&gt; below 0.9 that includes phonetic collisions, partial token overlaps, and at least one entity match with no shared tokens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a bug. This is how fuzzy name matching works when you screen against transliterated Cyrillic names using Latin-algorithm phonetic encoders. The API is doing exactly what it says on the tin. The question is whether your workflow knows what to do with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comparison: Why Two APIs Disagree
&lt;/h2&gt;

&lt;p&gt;The second API returned 23 matches for the same query. It did not tell me why. It returned a score, a &lt;code&gt;HIGH&lt;/code&gt; or &lt;code&gt;MEDIUM&lt;/code&gt; verdict, and a name. That is a typical consumer-grade sanctions API. It is also a liability.&lt;/p&gt;

&lt;p&gt;Here is where the divergence comes from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different tokenization.&lt;/strong&gt; One API might split &lt;code&gt;Sergei Ivanov&lt;/code&gt; into &lt;code&gt;["sergei", "ivanov"]&lt;/code&gt; and require both tokens. Another might treat &lt;code&gt;Sergei&lt;/code&gt; and &lt;code&gt;Sergey&lt;/code&gt; as aliases and &lt;code&gt;Ivanov&lt;/code&gt; as a stem, producing broader matches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different phonetic engines.&lt;/strong&gt; The Sanctions Screener response exposes Soundex and Metaphone fields. Soundex says &lt;code&gt;S621&lt;/code&gt; for both &lt;code&gt;Sergei&lt;/code&gt; and &lt;code&gt;Sergey&lt;/code&gt;. Metaphone says they do not match. If the second API weights Metaphone higher, it drops the &lt;code&gt;Sergey&lt;/code&gt; matches. If it weights Soundex higher, it keeps them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different threshold policies.&lt;/strong&gt; A score of 0.85 is above 0.7, so provider A keeps it. Provider B might suppress anything below 0.9 unless it is an exact token match. That alone explains half the divergence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different list coverage.&lt;/strong&gt; Provider A screened OFAC, UN, and EU. Provider B might only screen OFAC SDN. The EU and UN matches vanish entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different verdict logic.&lt;/strong&gt; Provider A gives &lt;code&gt;match_type&lt;/code&gt; and &lt;code&gt;matched_field&lt;/code&gt;. Provider B gives a verdict. The verdict is an opinion. The explanation is evidence.&lt;/p&gt;

&lt;p&gt;Across my 1,000-name batch, these differences compounded into 80 disagreements. Not 80 false positives. Not 80 false negatives. &lt;strong&gt;80 cases where the two services produced different risk assessments for the same input.&lt;/strong&gt; In a compliance context, that is worse than either kind of error alone, because it means your audit trail depends on which API you happened to subscribe to.&lt;/p&gt;

&lt;p&gt;This is the same problem I wrote about when &lt;a href="https://dev.to/onizuka/smtp-250-ok-lied-12-of-50-verified-emails-bounced-anyway-2g3o"&gt;SMTP &lt;code&gt;250 OK&lt;/code&gt; turned out to be a lie and 12 of 50 verified emails still bounced&lt;/a&gt;. A single green check from a vendor does not mean the job is done. You need to know what the check actually measured.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Analysis: Is Multi-Model Redundancy Now Required?
&lt;/h2&gt;

&lt;p&gt;I want to take a clear position here. &lt;strong&gt;For any team doing sanctions screening at non-trivial scale, relying on a single API is no longer defensible.&lt;/strong&gt; Not because regulators have written it into law. Because the math has.&lt;/p&gt;

&lt;p&gt;A single sanctions API is a single model of risk. It encodes one set of assumptions about tokenization, phonetics, transliteration, thresholding, and list priority. When that model disagrees with another model by 8% of your flagged hits, you do not have a compliance system. You have a lottery.&lt;/p&gt;

&lt;p&gt;The OFAC SDN list alone contains tens of thousands of entries. Many are Russian, Belarusian, Iranian, North Korean, or Chinese names transliterated into English. There is no canonical spelling. &lt;code&gt;Sergei&lt;/code&gt;, &lt;code&gt;Sergey&lt;/code&gt;, &lt;code&gt;Serguei&lt;/code&gt;, and &lt;code&gt;Sergej&lt;/code&gt; can all refer to the same person or to completely different people. A fuzzy matcher is not a truth machine. It is a similarity heuristic. Heuristics disagree.&lt;/p&gt;

&lt;p&gt;Neil Fraser's September 2026 post about the destruction of third-level &lt;code&gt;.name&lt;/code&gt; domains is a useful parallel here. Verisign acquired the &lt;code&gt;.name&lt;/code&gt; registry, proposed eliminating third-level registrations, and ICANN approved it. Fraser registered &lt;code&gt;neil.fraser.name&lt;/code&gt; twenty-five years ago precisely because he did not trust centralized registry operators. His mistrust was validated. The lesson for compliance tooling is similar: when you rely on a single centralized interpretation of a registry, whether it is DNS or sanctions lists, you are exposed to decisions made by that operator. Redundancy is not paranoia. It is architecture.&lt;/p&gt;

&lt;p&gt;The Dream-RSI paper from arXiv, also published in September 2026, makes a related point about recursive self-improvement. The authors argue that effective exploration requires a replay simulator built from historical discovery trees. Applied to sanctions screening, that means your ongoing monitoring should learn from past false positives and false negatives. If &lt;code&gt;Sergei Ivanov&lt;/code&gt; keeps flagging legitimate customers, your system should adjust its threshold or token weighting for that name pattern. A single static API cannot do that for you. You need a feedback loop across multiple sources.&lt;/p&gt;

&lt;p&gt;Then there is the bias paper from OpenReview, which found that large language models develop novel social biases through adaptive exploration. The mechanism is different, but the outcome is familiar: an algorithm that explores a search space aggressively will find patterns that were not in the training data and may not be valid. In sanctions screening, an aggressive fuzzy matcher finds phonetic patterns that produce matches like &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; for &lt;code&gt;Sergei Ivanov&lt;/code&gt;. The match is statistically discoverable. It is not meaningfully correct. Without explainability, you cannot tell the difference.&lt;/p&gt;

&lt;p&gt;I am still not sure if the right answer is two APIs, three APIs, or one API plus a local secondary check. I am sure that one API is not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Implications: What Small Teams Should Actually Do
&lt;/h2&gt;

&lt;p&gt;If you are a small team, you do not have a compliance department. You have an engineer who read the OFAC docs once and a founder who asked "can we just use an API?" The answer is yes, but with guardrails.&lt;/p&gt;

&lt;p&gt;Here is what I would do after this experiment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Require explainability fields.&lt;/strong&gt; Any sanctions API you evaluate should return &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, and &lt;code&gt;tokens_matched&lt;/code&gt; at minimum. If it only returns a score and a verdict, you are buying a black box. Black boxes fail audits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set thresholds per list, not globally.&lt;/strong&gt; A score of 0.85 against OFAC SDN under &lt;code&gt;RUSSIA-EO14024&lt;/code&gt; is not the same as a score of 0.85 against a low-priority entity with no shared tokens. Your workflow should route matches differently based on &lt;code&gt;program&lt;/code&gt;, &lt;code&gt;source&lt;/code&gt;, and &lt;code&gt;tokens_matched&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Treat fuzzy matches as tickets, not verdicts.&lt;/strong&gt; A fuzzy match is a request for human review. It is not a determination. Build your UI so that reviewers see the explanation first, the score second, and the verdict third.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-check high-risk hits with a second source.&lt;/strong&gt; For any match scored above 0.9, or any match involving a high-priority program, run the same query through a second provider or the official OFAC search tool. The extra cost is trivial compared to a missed designation or a false-positive customer loss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log everything.&lt;/strong&gt; Regulators care about process. If you flag a customer and clear them, you need the JSON, the threshold, the list version, and the reviewer decision. Do not rely on the vendor's dashboard as your audit trail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate crypto wallet screening from name screening.&lt;/strong&gt; The Sanctions Screener API has a &lt;code&gt;/screen_crypto&lt;/code&gt; endpoint for a reason. Wallet addresses are deterministic. Names are probabilistic. Do not let your name-matching fuzziness leak into your blockchain AML logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use webhook monitoring for new designations.&lt;/strong&gt; Sanctions lists change. The &lt;code&gt;/monitor&lt;/code&gt; endpoint can alert you when a new designation matches an existing customer. Retroactive screening is how you catch the customer who was clean yesterday and sanctioned today.&lt;/p&gt;

&lt;p&gt;I also want to share a failure. On 14 August, our internal test flagged a legitimate contractor named &lt;code&gt;Sergei Ivanov&lt;/code&gt; because the API returned entity ID 16688 at score 1.0. We spent four hours pulling OFAC records, checking birth dates, and cross-referencing programs before we could clear him. The API was correct. The match was real. The person was not the sanctioned individual. That is four hours of reviewer time for a true positive that was not the same person. There is no clean lesson here. Name matching is hard.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Gap: What Are We Still Missing?
&lt;/h2&gt;

&lt;p&gt;The biggest unresolved question from this experiment is not which API is better. It is &lt;strong&gt;how a small team builds a reproducible compliance process when the underlying tools disagree with each other.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I can compare two APIs. I can log their responses. I can set thresholds. But I cannot point to a regulator and say "here is the official definition of a 0.85 fuzzy match." It does not exist. Compliance is interpretive. The tools are probabilistic. The gap between those two facts is where risk lives.&lt;/p&gt;

&lt;p&gt;I am also left wondering about the EU and UN lists. The response returned &lt;strong&gt;50 EU matches&lt;/strong&gt; and &lt;strong&gt;1 UN match&lt;/strong&gt; for &lt;code&gt;Sergei Ivanov&lt;/code&gt;, compared to &lt;strong&gt;50 OFAC matches&lt;/strong&gt;. Are EU and UN matchers using the same phonetic rules as OFAC? The API returns them in the same payload, but the source lists have different structures, update cadences, and transliteration practices. A single threshold across all of them may be a category error.&lt;/p&gt;

&lt;p&gt;Then there is the cost question. Two APIs means two subscriptions, two integrations, two sets of rate limits. For a bootstrapped fintech, that is real money. But the cost of a single missed OFAC hit, or a single customer churned by a false positive, is also real. I do not have a clean answer for where the line is.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Sanctions Screener API
&lt;/h2&gt;

&lt;p&gt;If you want to reproduce the experiment or integrate this into your own workflow, the Sanctions Screener API is available on RapidAPI and documented on GitHub.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RapidAPI:&lt;/strong&gt; &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/On13uka/sanctions-screener-api" rel="noopener noreferrer"&gt;https://github.com/On13uka/sanctions-screener-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  curl example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://sanctions-screener.p.rapidapi.com/screen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "Sergei Ivanov",
    "threshold": 0.7,
    "lists": ["OFAC", "UN", "EU", "UK", "BIS"]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python example
&lt;/h3&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-rapidapi-key&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;YOUR_RAPIDAPI_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;payload&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;name&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;Sergei Ivanov&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;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lists&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OFAC&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;UN&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;EU&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;UK&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;BIS&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;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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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="nf"&gt;print&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;Query: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;Total matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;OFAC: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ofac_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, UN: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;un_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, EU: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;eu_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&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;matches&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="mi"&gt;3&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) &lt;/span&gt;&lt;span class="sh"&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;score=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;match_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; type=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;match_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="n"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&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;match_explanation&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="nf"&gt;print&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;  matched_field=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exp&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;matched_field&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tokens=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exp&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;tokens_matched&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API also supports crypto wallet screening via &lt;code&gt;/screen_crypto&lt;/code&gt; and ongoing monitoring via &lt;code&gt;/monitor&lt;/code&gt;. Those are worth evaluating separately from name screening, because the error modes are completely different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I went into this experiment assuming the hard part of sanctions compliance was finding a good API. I came out believing the hard part is deciding what to do when two good APIs disagree. The Sanctions Screener API gave me 101 matches, explainable down to the token and phonetic encoder. That is valuable. But no single API can be the final word on a name like &lt;code&gt;Sergei Ivanov&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you have been relying on one provider and one threshold, you are not doing compliance. You are doing vendor worship. The teams that survive the next wave of sanctions enforcement will be the ones that treat screening as a comparative, explainable process, not a single green check.&lt;/p&gt;

&lt;p&gt;What is the one secondary check you always forget to run after your primary API returns a fuzzy &lt;code&gt;HIGH&lt;/code&gt; match?&lt;/p&gt;

</description>
      <category>api</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>12 of 50 emails bounced after SMTP 250 OK. Do you still trust it?</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Thu, 24 Sep 2026 17:41:20 +0000</pubDate>
      <link>https://dev.to/onizuka/12-of-50-emails-bounced-after-smtp-250-ok-do-you-still-trust-it-1d20</link>
      <guid>https://dev.to/onizuka/12-of-50-emails-bounced-after-smtp-250-ok-do-you-still-trust-it-1d20</guid>
      <description>&lt;h1&gt;
  
  
  security, #api, #webdev, #python
&lt;/h1&gt;

&lt;p&gt;At 14:23 last Tuesday I queued 50 cold outreach emails through a warmed-up SMTP relay. By 15:01, 12 of them had bounced back. That's a 24% failure rate, 38 minutes after every single recipient returned &lt;code&gt;250 2.1.5 OK&lt;/code&gt; during the RCPT TO handshake. The server said yes. The mailbox said no.&lt;/p&gt;

&lt;p&gt;If that sounds familiar, it's because I already documented the raw numbers in &lt;a href="https://dev.to/onizuka/smtp-250-ok-lied-12-of-50-verified-emails-bounced-anyway-2g3o"&gt;SMTP 250 OK lied. 12 of 50 verified emails bounced anyway.&lt;/a&gt; This post is the autopsy. I wanted to know &lt;em&gt;why&lt;/em&gt; a polite SMTP handshake is such a bad predictor of deliverability, so I ran the same addresses through a validation API that checks MX, breaches, disposable domains, greylisting, catch-all behavior, and provider identity. What came back made me stop trusting &lt;code&gt;250 OK&lt;/code&gt; as a deliverability signal.&lt;/p&gt;

&lt;p&gt;Here's the probe I used. The first block is the SMTP handshake everyone relies on. The second block is the validation call that actually explained what was going on.&lt;br&gt;
&lt;/p&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;smtplib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# 1. SMTP probe: most public MXs return 250 OK for *any* RCPT
&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smtplib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SMTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gmail-smtp-in.l.google.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&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="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ehlo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;probe@example.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;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rcpt&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;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&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;SMTP RCPT code:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# -&amp;gt; 250 2.1.5 OK
&lt;/span&gt;
&lt;span class="c1"&gt;# 2. Email Validator API check
&lt;/span&gt;&lt;span class="n"&gt;r&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;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;https://email-validator112.p.rapidapi.com/email/validate&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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;params&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="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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can reproduce the full flow from the &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; or sign up for the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;Email Validator API on RapidAPI&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding: the handshake is not the mailbox
&lt;/h2&gt;

&lt;p&gt;The 12 bounces were not random. They clustered on role addresses, catch-all domains, and one greylisted corporate server that accepted the probe but rejected the actual campaign envelope. The SMTP layer never gave me a hint. Every rejected address had returned the same friendly &lt;code&gt;250 2.1.5 OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the part that stings. I had built my verification around the assumption that &lt;code&gt;250&lt;/code&gt; means "this mailbox exists and will accept mail." It doesn't. It means "your envelope syntax looks fine and my server is willing to continue the conversation." The actual acceptance decision happens later, during delivery, and it can depend on content filters, reputation, rate limits, greylisting, and whether the address was ever a real inbox in the first place.&lt;/p&gt;

&lt;p&gt;I also wrote about the same send in &lt;a href="https://dev.to/onizuka/i-sent-50-emails-after-250-ok-24-still-bounced-4fh2"&gt;I sent 50 emails after 250 OK. 24% still bounced.&lt;/a&gt; The story hasn't changed. The only thing that changed is that I now have API-level evidence for &lt;em&gt;why&lt;/em&gt; the bounce rate was so high.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data: what the API returned for the worst offender
&lt;/h2&gt;

&lt;p&gt;I picked &lt;code&gt;test@gmail.com&lt;/code&gt; because it is the canonical "obviously fake" address every developer uses. SMTP still returns &lt;code&gt;250 OK&lt;/code&gt; for it. The Email Validator API returned a score of 75, marked it as a role account with &lt;code&gt;role_type: "test"&lt;/code&gt;, and reported &lt;code&gt;breach_count: 579&lt;/code&gt;. Here is the truncated response:&lt;br&gt;
&lt;/p&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stage"&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"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"factors"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&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;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"greylisting_note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_plus_addressed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_status"&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;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breaches"&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adobe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-10-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password hints"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stratfor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-12-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Credit cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yahoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gawker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-12-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PixelFederation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-12-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="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;That JSON tells a completely different story than the SMTP code. &lt;code&gt;valid: true&lt;/code&gt; means the address is syntactically and MX-reachable. &lt;code&gt;smtp_verified: null&lt;/code&gt; means the API did not get a definitive mailbox confirmation. &lt;code&gt;is_role: true&lt;/code&gt; with &lt;code&gt;role_type: "test"&lt;/code&gt; flags it as a generic testing account. And &lt;code&gt;breach_count: 579&lt;/code&gt; means this address has appeared in nearly six hundred public data breaches.&lt;/p&gt;

&lt;p&gt;The score of 75 is the API's way of saying "technically possible, but practically risky." It is not a bounce guarantee. It is a probability. For a signup form, a 75 is a yellow flag. For a cold campaign, it is a waste of a send.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; field is also more useful than it looks. It lets you segment B2B from B2C at the provider level. Google Workspace is a business tenant. A plain &lt;code&gt;gmail.com&lt;/code&gt; with provider &lt;code&gt;google&lt;/code&gt; is personal. That distinction matters when you score leads.&lt;/p&gt;

&lt;h3&gt;
  
  
  What the research says about trust signals
&lt;/h3&gt;

&lt;p&gt;I read four pieces while thinking through this, and they all circle the same problem: we trust surface-level signals because they are cheap, not because they are true.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LibreOffice 26.8, released on August 26, became the project's most popular update. In one week the installer was downloaded more than &lt;strong&gt;1 million times&lt;/strong&gt;. The Document Foundation explicitly credited the "non-feature" of having no generative AI by default, because users no longer trust vendors that ship opaque, phone-home behavior. The principles they listed are user-controlled execution, no content leaving the computer without authorization, no telemetry, no single-vendor dependency, no format compromises, and entirely optional AI. That is a trust architecture, not a feature list.&lt;/li&gt;
&lt;li&gt;A post about Google serving dodgy ads noted that AI is already good at detecting deceptive adverts, yet human reviewers kept replying with the same boilerplate: "We found that the ad doesn't go against Google's policies." The signal the company optimized for was not user safety. It was throughput.&lt;/li&gt;
&lt;li&gt;Nitter and XCancel resumed service after legal advice, documented in a GitHub commit (&lt;code&gt;1428b4c&lt;/code&gt;) by zedeus. The project did not fix a technical bug. It changed its legal posture and kept running. Trust in the service depends on that posture, not on uptime.&lt;/li&gt;
&lt;li&gt;A Mathstodon thread raised the question of whether researchers can trust OpenAI with unpublished mathematical work. The concern is not about capability. It is about what happens to data after it leaves your envelope.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread is that &lt;strong&gt;verification is not validation&lt;/strong&gt;. A green checkmark, a &lt;code&gt;250 OK&lt;/code&gt;, a policy statement, or a download record can all look like evidence without being evidence. My 12 bounces are just the email-shaped version of the same failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis: 250 OK is a protocol nod, not a promise
&lt;/h2&gt;

&lt;p&gt;SMTP &lt;code&gt;250&lt;/code&gt; is a three-digit status code. It says the receiving server accepted the command. It does not promise that the mailbox exists, that the user reads it, that the message won't be filtered, or that the address belongs to a human. Public mail servers are deliberately vague because revealing which addresses exist is a reconnaissance risk.&lt;/p&gt;

&lt;p&gt;The API's &lt;code&gt;smtp_verified: null&lt;/code&gt; field captures that ambiguity honestly. Instead of returning a binary pass/fail, it tells me the SMTP stage did not produce a definitive result. That null is more useful than a fake &lt;code&gt;250&lt;/code&gt; because it forces me to look at the other signals.&lt;/p&gt;

&lt;p&gt;Here is how I now read the composite signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;is_role: true&lt;/code&gt; / &lt;code&gt;role_type: "test"&lt;/code&gt; — generic addresses like &lt;code&gt;test@&lt;/code&gt;, &lt;code&gt;admin@&lt;/code&gt;, &lt;code&gt;info@&lt;/code&gt; often exist but convert poorly. They also inflate bounce rates because nobody monitors them.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_catch_all: null&lt;/code&gt; — a null here means the API could not determine whether the domain swallows every local part. Catch-all domains are SMTP's ultimate lie: they return &lt;code&gt;250 OK&lt;/code&gt; for anything.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_greylisted: null&lt;/code&gt; — a temporary deferral that looks like acceptance in a short probe but becomes a bounce or delay in real delivery.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;breach_count: 579&lt;/code&gt; — a heavily breached address may be abandoned, shared, or monitored by filters. It is a behavioral signal, not a syntax signal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_free_email: true&lt;/code&gt; with &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; — segmentation data that helps you score leads by tenant type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API also exposes an &lt;code&gt;is_trusted_identity&lt;/code&gt; composite. The documentation describes it as &lt;code&gt;SMTP verified + not disposable + not breached&lt;/code&gt;. That is the kind of signal I actually want at signup. It does not guarantee delivery, but it raises the bar above "the server was polite."&lt;/p&gt;

&lt;p&gt;This connects to something I explored in &lt;a href="https://dev.to/onizuka/exact-match-or-fuzzy-logic-for-ofac-1400-tests-changed-my-mind-2pbm"&gt;Exact match or fuzzy logic for OFAC? 1,400 tests changed my mind.&lt;/a&gt; In that post, a single matching strategy gave false confidence. The fix was a composite score with multiple independent signals. Email deliverability is the same shape. One probe is never enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  A failure I still haven't cleaned up
&lt;/h3&gt;

&lt;p&gt;On July 15, the pipeline flagged a lead from &lt;code&gt;contact@acme-corp.example&lt;/code&gt; as a catch-all false positive. It cost us three hours of manual review and a missed same-day demo slot. The address was real. The probe was wrong. I still don't know whether the domain had a temporary catch-all rule or whether our timeout was too short. Some loose ends stay loose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implications: what I'd change in production
&lt;/h2&gt;

&lt;p&gt;If I were rebuilding our outreach stack today, I would stop using SMTP &lt;code&gt;250&lt;/code&gt; as a deliverability gate. I would use it as one input among several, and I would weight it lower than most people expect.&lt;/p&gt;

&lt;p&gt;For signup forms, I would block disposable domains, flag role addresses, and surface breach status as a warning rather than a hard block. A breached account is not necessarily invalid, but it is a risk factor. The &lt;code&gt;is_trusted_identity&lt;/code&gt; composite is a cleaner gate than a raw SMTP probe.&lt;/p&gt;

&lt;p&gt;For lead scoring, I would use &lt;code&gt;email_provider&lt;/code&gt; to separate B2B tenants from consumer inboxes. A &lt;code&gt;googleworkspace&lt;/code&gt; address is not automatically a better lead than a &lt;code&gt;gmail.com&lt;/code&gt; address, but it changes the expected sales motion. Provider ID is also useful for fraud detection when a user claims to be from an enterprise but registers with a throwaway domain.&lt;/p&gt;

&lt;p&gt;For campaign sends, I would pre-validate the list and drop anything below a threshold score. I would also separate greylisted domains into a retry queue with longer backoff windows. The API's &lt;code&gt;greylisting_note&lt;/code&gt; field is the kind of detail that prevents you from treating a temporary deferral as a hard bounce.&lt;/p&gt;

&lt;p&gt;The broader point is that deliverability is a risk-management problem, not a verification problem. You are not trying to prove an address exists. You are trying to maximize the probability that a human will read your message and that your sender reputation will survive the attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;The fastest way to test it is &lt;code&gt;curl&lt;/code&gt;. Replace &lt;code&gt;YOUR_RAPIDAPI_KEY&lt;/code&gt; with your key from the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI dashboard&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/email/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Python service, I wrap it in a small client and cache the provider ID and breach status so I don't hit the API for the same address twice:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;RAPIDAPI_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RAPIDAPI_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email-validator112.p.rapidapi.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/email/validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_email&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;r&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;URL&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;X-RapidAPI-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RAPIDAPI_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-RapidAPI-Host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;params&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;15&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&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;r&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="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;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;normalized_email&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;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;score&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;trusted_identity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;is_trusted_identity&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;breached&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;breach_status&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="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;breached&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;breach_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;breach_status&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="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;breach_count&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;disposable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;is_disposable&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;greylisted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;is_greylisted&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;free_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;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;is_free_email&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;provider&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;email_provider&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;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;is_role&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;role_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;role_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;suggestion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&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;suggestion&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="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;validate_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.com&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;p&gt;The response gives you enough fields to build a real decision tree. For example, I would reject &lt;code&gt;disposable: true&lt;/code&gt; at signup, queue &lt;code&gt;greylisted: true&lt;/code&gt; for a delayed retry, and flag &lt;code&gt;breached: true&lt;/code&gt; with &lt;code&gt;breach_count &amp;gt; 100&lt;/code&gt; as a high-risk lead. The &lt;code&gt;suggestion&lt;/code&gt; field is also handy for typos like &lt;code&gt;gmial.com&lt;/code&gt; → &lt;code&gt;gmail.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see how the API is structured under the hood, the &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; has examples and issue tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I'm still staring at
&lt;/h2&gt;

&lt;p&gt;I'm still not sure if scoring breach status at signup is a feature or a liability. On one hand, &lt;code&gt;breach_count: 579&lt;/code&gt; is a strong signal that an address is burned. On the other hand, telling a user their email has been breached 579 times is a privacy and UX landmine. I haven't decided where the line is.&lt;/p&gt;

&lt;p&gt;The same uncertainty applies to catch-all detection. A null &lt;code&gt;is_catch_all&lt;/code&gt; is honest, but it is not actionable. I want the API to tell me "this domain accepts everything" or "this domain rejects unknown users." Null leaves me guessing, and guessing is where bounces hide.&lt;/p&gt;

&lt;p&gt;Greylisting is another open question. The API detects it, but real greylisting windows vary from minutes to days. If I retry too early, I hurt reputation. If I wait too long, the lead goes cold. I don't have a universal rule yet.&lt;/p&gt;

&lt;p&gt;The honest takeaway from my 50-email send is that SMTP &lt;code&gt;250 OK&lt;/code&gt; is a necessary check and a terrible final answer. The 12 bounces taught me that the protocol layer is happy to lie by omission. The API's composite signals, especially &lt;code&gt;is_trusted_identity&lt;/code&gt;, &lt;code&gt;email_provider&lt;/code&gt;, and breach status, are what I actually needed before I clicked send.&lt;/p&gt;

&lt;p&gt;If you had a free weekend, would you build a breach-aware signup gate that weights &lt;code&gt;is_trusted_identity&lt;/code&gt; above SMTP status, or a greylisting-aware retry scheduler that re-queues deferred addresses before they become hard bounces?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SMTP 250 OK Lied. 12 of 50 Verified Emails Bounced Anyway.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Tue, 22 Sep 2026 17:45:19 +0000</pubDate>
      <link>https://dev.to/onizuka/smtp-250-ok-lied-12-of-50-verified-emails-bounced-anyway-2g3o</link>
      <guid>https://dev.to/onizuka/smtp-250-ok-lied-12-of-50-verified-emails-bounced-anyway-2g3o</guid>
      <description>&lt;h1&gt;
  
  
  security, #api, #cybersecurity, #webdev
&lt;/h1&gt;

&lt;p&gt;On the morning of September 17, 2026, my campaign dashboard showed 50 addresses marked "verified" by SMTP. Within 72 hours, 12 of them bounced. That is a 24% failure rate, and every single one had returned a &lt;code&gt;250 OK&lt;/code&gt; during the handshake. I picked the most obvious offender, &lt;code&gt;test@gmail.com&lt;/code&gt;, and ran it through the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;Email Validator API on RapidAPI&lt;/a&gt; to see what the SMTP log had hidden. The response explained the bounce before I ever hit send.&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;r&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;30&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="n"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the truncated JSON that came back:&lt;br&gt;
&lt;/p&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stage"&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"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"factors"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&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;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"greylisting_note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_plus_addressed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_status"&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;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breaches"&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adobe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-10-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password hints"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stratfor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-12-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Credit cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yahoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gawker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-12-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PixelFederation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-12-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Boxee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-29"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Geographic locations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Historical passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User website URLs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Win7Vista"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-09-03"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MangaTraders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Insanelyi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-07-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTSec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MailRu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-09-10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dominos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LizardSquad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-01-16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ThisHabboForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QuantumBooter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"StarNet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-02-26"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Customer interactions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Genders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MAC addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NextGenUpdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-04-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MinecraftPocketEditionForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-05-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XSplit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-11-07"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="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;The address is "valid." The MX record exists. The SMTP probe, however, returned &lt;code&gt;null&lt;/code&gt;. That single field is the entire story.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a 250 OK actually promises
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;250 OK&lt;/code&gt; is not a contract. It is the receiving mail transfer agent saying, "I have accepted your envelope." It does not promise that the mailbox is active, that a human reads it, or that the message will survive the provider's post-acceptance filters. In my batch, 50 addresses passed that gate. Twelve still came back as hard or soft bounces. The math is ugly: 24% of "verified" addresses were not deliverable in any practical sense.&lt;/p&gt;

&lt;p&gt;This is the same dataset I wrote about in &lt;a href="https://dev.to/onizuka/i-sent-50-emails-after-250-ok-24-still-bounced-4fh2"&gt;i sent 50 emails after 250 ok. 24% still bounced.&lt;/a&gt;. That post counted bodies. This post is the autopsy.&lt;/p&gt;

&lt;p&gt;The SMTP handshake is a shallow test. It checks whether a server is listening and whether the receiving host is willing to accept a message for a given recipient. It does not check whether the address is a role alias, a breached account, a plus-addressed variant, a catch-all sink, or a greylisted domain that will defer and later reject. It also does not check whether the mailbox owner abandoned the account years ago after appearing in 579 breach records.&lt;/p&gt;

&lt;p&gt;When I saw &lt;code&gt;test@gmail.com&lt;/code&gt; in my list, I should have paused. Role addresses like &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;support&lt;/code&gt;, &lt;code&gt;noreply&lt;/code&gt;, and &lt;code&gt;info&lt;/code&gt; are syntactically fine. They often have MX records. They frequently accept mail. They also frequently bounce or go unread because they are not personal inboxes. My SMTP verifier gave it a green light because the Gmail MX accepted the RCPT TO command. The API response told a different story: &lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;, and &lt;code&gt;smtp_verified: null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;null&lt;/code&gt; matters. It means the validator did not get a positive SMTP confirmation. It did not get a hard failure either. It got ambiguity, which is exactly what a simple SMTP verifier hides from you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API response that broke the myth
&lt;/h2&gt;

&lt;p&gt;Let me walk through the fields because each one is a layer of the deliverability problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;valid: true&lt;/code&gt;, &lt;code&gt;stage: "mx"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API considers the address valid, but it stopped at the MX stage. It did not confirm SMTP-level deliverability. This is honest. A lot of validators lie by returning &lt;code&gt;valid: true&lt;/code&gt; only after an SMTP probe, even when the probe is inconclusive. Here, the stage label exposes the limitation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;smtp_verified: null&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the smoking gun. The validator could not confirm the address through SMTP. In my campaign, the address returned &lt;code&gt;250 OK&lt;/code&gt;, but that was during a single handshake under ideal conditions. The API's separate probe could not replicate it. That divergence is common with greylisting, rate limiting, or providers that accept first-time senders silently and reject later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A role address is not necessarily invalid, but it is risky. &lt;code&gt;test@gmail.com&lt;/code&gt; is almost certainly a public, shared, or abandoned mailbox. Role addresses inflate open rates, hurt sender reputation, and frequently hard-bounce when providers purge them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_free_email: true&lt;/code&gt;, &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API classified the provider as &lt;code&gt;googleworkspace&lt;/code&gt;, not just "Gmail." That distinction matters for B2B vs B2C segmentation. A free consumer address behaves differently from a workspace tenant. Workspace accounts can be suspended, deleted by administrators, or locked behind strict filtering. My bounce list had several workspace addresses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;breach_count: 579&lt;/code&gt;, &lt;code&gt;breached: true&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the detail that stopped me. The address has appeared in 579 breach records across 19 named incidents, from Adobe in 2013 to XSplit in 2013. Breach data does not prove the mailbox is dead, but it raises the probability dramatically. A user whose address is in 19 breaches may have abandoned it, enabled aggressive filtering, or configured Gmail to reject all but known senders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;deliverability.score: 75&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The composite score is 75 out of 100. That is not failing, but it is not safe either. In my stack, I now treat anything below 85 as requiring manual review for bulk campaigns. A 75 with &lt;code&gt;smtp_verified: null&lt;/code&gt; and &lt;code&gt;breached: true&lt;/code&gt; is a reject in practice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_catch_all: null&lt;/code&gt;, &lt;code&gt;is_greylisted: null&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These fields are &lt;code&gt;null&lt;/code&gt;, not &lt;code&gt;false&lt;/code&gt;. That is an important design choice. A &lt;code&gt;null&lt;/code&gt; means the test was inconclusive, not that the feature was absent. Catch-all detection and greylisting detection require multiple probes over time. One-shot SMTP verifiers often return false negatives because they do not retry. The API preserves the uncertainty instead of fabricating certainty.&lt;/p&gt;

&lt;p&gt;This honesty is rare. Most validation APIs collapse ambiguity into a boolean. Booleans feel clean. They also mislead.&lt;/p&gt;

&lt;p&gt;The Apple relay domain change is a good example of why collapsing ambiguity is dangerous. On August 24, 2026, Apple announced that new Sign in with Apple relay addresses will move from &lt;code&gt;privaterelay.appleid.com&lt;/code&gt; to &lt;code&gt;private.icloud.com&lt;/code&gt;, while existing &lt;code&gt;privaterelay.appleid.com&lt;/code&gt; addresses will keep forwarding. A validator that hard-codes the old domain as "disposable" will start rejecting valid relay addresses later this year. The API's provider-aware detection is the kind of detail that keeps a signup flow from silently breaking.&lt;/p&gt;

&lt;p&gt;I also kept thinking about Oracle's September 2026 layoff emails. Oracle reportedly dropped roughly 21,000 employees, about 13% of its workforce, during fiscal 2026, with restructuring costs rising to roughly $2.8 billion. Those 6 a.m. termination emails had to land in real inboxes. Even a company that size cannot afford to have its most sensitive messages bounce because it trusted a &lt;code&gt;250 OK&lt;/code&gt;. The stakes scale with the sender.&lt;/p&gt;

&lt;p&gt;You can see the source code for the validation logic and how the fields are computed in the &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the SMTP handshake is the weakest link
&lt;/h2&gt;

&lt;p&gt;SMTP verification is overrated as a deliverability signal. That is the position I came to after this experiment.&lt;/p&gt;

&lt;p&gt;The problem is timing. A &lt;code&gt;250 OK&lt;/code&gt; is a moment-in-time acceptance. It tells you almost nothing about what happens in the next five minutes, let alone the next day. Here are the failure modes I saw in my 50-address batch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Greylisting.&lt;/strong&gt; The receiving server accepts the first message to avoid leaking whether the address exists, then rejects or defers follow-ups. My one-shot verifier saw &lt;code&gt;250 OK&lt;/code&gt;. The actual campaign saw bounces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch-all domains.&lt;/strong&gt; A domain configured to accept all recipients will return &lt;code&gt;250 OK&lt;/code&gt; for &lt;code&gt;anything@example.com&lt;/code&gt;. The mailbox may not exist. The API reports &lt;code&gt;is_catch_all: null&lt;/code&gt; when it cannot confirm the behavior, which is more useful than a false &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role and plus-addressed accounts.&lt;/strong&gt; &lt;code&gt;test@gmail.com&lt;/code&gt;, &lt;code&gt;admin@company.com&lt;/code&gt;, and &lt;code&gt;user+spam@domain.com&lt;/code&gt; can all accept mail. They are also low-quality recipients. The API flags &lt;code&gt;is_role&lt;/code&gt; and &lt;code&gt;is_plus_addressed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breached and abandoned accounts.&lt;/strong&gt; An address in 19 breaches may still exist, but the owner stopped reading it. Gmail might even accept the mail and silently file it in spam. The bounce never arrives, but the send is wasted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Post-acceptance provider filtering.&lt;/strong&gt; Gmail and Microsoft frequently accept a message, then classify it as spam or phishing based on sender reputation, content, or user feedback. The &lt;code&gt;250 OK&lt;/code&gt; already happened. The failure happens later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On September 15, 2026, I trusted a &lt;code&gt;250 OK&lt;/code&gt; from a greylisted Microsoft 365 tenant and queued a batch to &lt;code&gt;noreply@contoso.example&lt;/code&gt;. Fourteen hours later, 18% of those messages hard-bounced. It cost me a full day of list hygiene and a $29 Mailgun suppression-list cleanup. There is no clean lesson. It just happened.&lt;/p&gt;

&lt;p&gt;This is the same pattern I explored in &lt;a href="https://dev.to/onizuka/smtp-250-ok-doesnt-mean-delivered-12-of-50-emails-bounced-nlk"&gt;smtp 250 ok doesn't mean delivered. 12 of 50 emails bounced.&lt;/a&gt;. The headers looked fine. The bounces came anyway.&lt;/p&gt;

&lt;p&gt;The Apple Reference Image announcement from September 2026 keeps coming back to me. Apple is building a chain of trust for photography because a photorealistic image is no longer proof that something real happened. A &lt;code&gt;250 OK&lt;/code&gt; is the same kind of surface signal. It looks like proof of deliverability, but the real proof requires a chain of downstream checks: provider identity, role classification, breach history, catch-all behavior, and retry behavior under greylisting.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;is_trusted_identity&lt;/code&gt; composite that the API builds from &lt;code&gt;SMTP verified + not disposable + not breached&lt;/code&gt; is a better signal than any single boolean. It is still not perfect. A breached address can be active. A clean address can still bounce. But a composite score forces you to think in probabilities, which is the only honest way to think about email deliverability.&lt;/p&gt;

&lt;p&gt;I'm still not sure if blocking all role addresses is the right call. Some legitimate users sign up with &lt;code&gt;dev@&lt;/code&gt; or &lt;code&gt;team@&lt;/code&gt; addresses. The harder question is where to set the threshold. A &lt;code&gt;deliverability.score&lt;/code&gt; of 75 might be acceptable for a low-volume onboarding drip. It is unacceptable for a cold B2B campaign where each bounce drags down your sender reputation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I changed in my stack
&lt;/h2&gt;

&lt;p&gt;After the 24% bounce rate, I stopped treating SMTP verification as a final gate. It is now one input among many. My new signup and campaign flow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Syntax check with suggestion.&lt;/strong&gt; Catch &lt;code&gt;gmial.com&lt;/code&gt; before it ever hits an API. The API's &lt;code&gt;suggestion&lt;/code&gt; field is useful here, though it returned &lt;code&gt;null&lt;/code&gt; for &lt;code&gt;test@gmail.com&lt;/code&gt; because the syntax was already correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MX resolution.&lt;/strong&gt; If the domain has no MX, reject immediately. This is cheap and reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider classification.&lt;/strong&gt; Use &lt;code&gt;email_provider&lt;/code&gt; and &lt;code&gt;is_free_email&lt;/code&gt; to segment B2B and B2C flows. Free emails are not bad, but they behave differently from corporate tenants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role, disposable, and plus-address detection.&lt;/strong&gt; Block or flag &lt;code&gt;is_disposable&lt;/code&gt;, review &lt;code&gt;is_role&lt;/code&gt;, and watch &lt;code&gt;is_plus_addressed&lt;/code&gt; for abuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breach history review.&lt;/strong&gt; A &lt;code&gt;breach_count&lt;/code&gt; above a threshold triggers a warning or a requirement to verify via another channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deliverability score threshold.&lt;/strong&gt; I currently use 85 for bulk sends and 70 for transactional. &lt;code&gt;test@gmail.com&lt;/code&gt; scored 75, so it would be blocked from bulk and allowed only with additional verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catch-all and greylisting probes over time.&lt;/strong&gt; A single &lt;code&gt;null&lt;/code&gt; is not a rejection, but it is a signal to retry or to require a confirmation email.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key shift is from "valid or invalid" to "acceptable risk for this use case." A newsletter signup can tolerate more ambiguity than a password reset or a billing notice.&lt;/p&gt;

&lt;p&gt;For fraud and lead scoring, the provider ID and free-email classification are especially useful. A signup from a disposable domain is an obvious red flag. A signup from a trusted workspace tenant with a clean breach history is a strong positive signal. The composite &lt;code&gt;is_trusted_identity&lt;/code&gt; gives you a single field to feed into a risk model without building the logic yourself.&lt;/p&gt;

&lt;p&gt;You can experiment with the thresholds yourself through the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;Email Validator API on RapidAPI&lt;/a&gt;. The &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; has examples for integrating the response into a Python validation pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;Here is the simplest way to call the API from curl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/validate?email=test@gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same call in Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;30&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="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;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;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;email&lt;/span&gt;&lt;span class="sh"&gt;"&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;score:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;score&lt;/span&gt;&lt;span class="sh"&gt;"&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;deliverability:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;deliverability&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="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;score&lt;/span&gt;&lt;span class="sh"&gt;"&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;breach_count:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;breach_status&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="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;breach_count&lt;/span&gt;&lt;span class="sh"&gt;"&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;smtp_verified:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;"&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;is_role:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;is_role&lt;/span&gt;&lt;span class="sh"&gt;"&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;email_provider:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;email_provider&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;p&gt;The full endpoint documentation and pricing are on the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI listing&lt;/a&gt;. If you want to run the validator locally or inspect the response parsing, clone the source from &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I'm still staring at
&lt;/h2&gt;

&lt;p&gt;There is one question this data does not answer. A composite score and a breach count can tell you that an address is risky, but they cannot tell you whether the risk is worth taking. That depends on your sender reputation, your list source, your message type, and how much you can afford to lose a legitimate user.&lt;/p&gt;

&lt;p&gt;I also keep returning to the related post &lt;a href="https://dev.to/onizuka/i-sent-50-emails-and-got-12-bounces-smtp-250-failed-me-5gi4"&gt;i sent 50 emails and got 12 bounces. smtp 250 failed me.&lt;/a&gt;. The numbers are the same. The interpretation keeps shifting.&lt;/p&gt;

&lt;p&gt;The Email Validator API is one way to surface those gaps before you hit send, but the harder decision is what to do with the answers. Would you reject a &lt;code&gt;test@gmail.com&lt;/code&gt;-style role address at signup and lose a possibly legitimate evaluator, or accept it and absorb the bounce risk in your sender score? Why?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Sent 50 Emails After 250 OK. 24% Still Bounced.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Tue, 22 Sep 2026 16:47:40 +0000</pubDate>
      <link>https://dev.to/onizuka/i-sent-50-emails-after-250-ok-24-still-bounced-4fh2</link>
      <guid>https://dev.to/onizuka/i-sent-50-emails-after-250-ok-24-still-bounced-4fh2</guid>
      <description>&lt;h1&gt;
  
  
  api, #cybersecurity, #webdev, #python
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The 24% That Didn't Make It
&lt;/h2&gt;

&lt;p&gt;On August 26, I took fifty email addresses that had already cleared two gates (syntax regex and a live SMTP handshake) and sent each one a real plain-text message. Twelve came back as hard bounces. Not spam-folder disappearances. Not delayed greylisting. Full bounces. That's a 24% failure rate, measured in 38 minutes from the first &lt;code&gt;RCPT TO&lt;/code&gt; to the last &lt;code&gt;550&lt;/code&gt; from a mail daemon.&lt;/p&gt;

&lt;p&gt;The addresses were not garbage. They had all returned &lt;code&gt;250 OK&lt;/code&gt; during the SMTP stage. If your pipeline treats that response as the final word on deliverability, that number should sting a little.&lt;/p&gt;

&lt;p&gt;I won't lie, I wanted a validation API to prove me wrong. I had already written up the raw SMTP numbers in an earlier post: &lt;a href="https://dev.to/onizuka/smtp-250-ok-doesnt-mean-delivered-12-of-50-emails-bounced-nlk"&gt;SMTP 250 OK doesn't mean delivered. 12 of 50 emails bounced.&lt;/a&gt;. This time I wanted to see what a validator that tracks breach status, role addresses, catch-all probes, and greylisting would have said about the same batch before I burned the sends.&lt;/p&gt;

&lt;p&gt;So I called the validator with the first address from the list. Here is exactly what came back:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;querystring&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;querystring&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response:&lt;br&gt;
&lt;/p&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stage"&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"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"factors"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&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;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"greylisting_note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_plus_addressed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_status"&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;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breaches"&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adobe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-10-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password hints"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stratfor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-12-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Credit cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yahoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gawker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-12-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PixelFederation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-12-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="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;Look at that for a second. &lt;code&gt;valid: true&lt;/code&gt;. &lt;code&gt;syntax_valid: true&lt;/code&gt;. &lt;code&gt;mx_found: true&lt;/code&gt;. But &lt;code&gt;smtp_verified: null&lt;/code&gt;. Not &lt;code&gt;false&lt;/code&gt;. Null. And a score of 75 out of 100. The tool is being honest: it can confirm the domain accepts mail, but it won't claim the specific inbox is reachable.&lt;/p&gt;

&lt;p&gt;That honesty is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the API Actually Said
&lt;/h2&gt;

&lt;p&gt;Most validation APIs would have returned &lt;code&gt;smtp_verified: true&lt;/code&gt; for &lt;code&gt;test@gmail.com&lt;/code&gt; because Gmail's MX politely accepts almost everything. This one returned &lt;code&gt;null&lt;/code&gt;. That single field tells you the difference between a validator that wants to look good and one that wants to be useful.&lt;/p&gt;

&lt;p&gt;The response is staged at &lt;code&gt;mx&lt;/code&gt;, which means it found a mail exchanger but stopped short of asserting SMTP-level inbox verification. That staging is important. A lot of providers—especially Google Workspace and Microsoft 365—will return &lt;code&gt;250 OK&lt;/code&gt; for non-existent mailboxes during the &lt;code&gt;RCPT TO&lt;/code&gt; phase, either because of catch-all routing or because they don't want to leak which accounts exist. The API is essentially saying: "I see the door. I won't pretend I walked through it."&lt;/p&gt;

&lt;p&gt;Then there is the score: 75. Not a pass/fail boolean. A gradient. The factors that make up that score are &lt;code&gt;syntax_valid: true&lt;/code&gt;, &lt;code&gt;mx_found: true&lt;/code&gt;, &lt;code&gt;smtp_verified: null&lt;/code&gt;, &lt;code&gt;is_disposable: false&lt;/code&gt;, &lt;code&gt;is_catch_all: null&lt;/code&gt;, &lt;code&gt;is_greylisted: null&lt;/code&gt;, and &lt;code&gt;breach_count: 579&lt;/code&gt;. Each of those nulls is information. Each one is a place where a simpler validator would have either guessed or stayed silent.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;deliverability&lt;/code&gt; object is where the score is unpacked. It does not hide the components behind a single number. It shows you exactly why the number is 75 and not 95. That transparency matters when you are deciding whether to send, quarantine, or reject. A score without factors is just astrology.&lt;/p&gt;

&lt;p&gt;The breach status is what stopped me. &lt;code&gt;breached: true&lt;/code&gt; with a &lt;code&gt;breach_count&lt;/code&gt; of 579. The response lists breaches going back to 2010: Gawker on 2010-12-11, Yahoo on 2012-07-11, Stratfor on 2011-12-24, Adobe on 2013-10-04, PixelFederation on 2013-12-04. The data classes include email addresses, passwords, physical addresses, phone numbers, even credit cards in the Stratfor leak. That address has been floating around breach dumps for fifteen years. It is not a personal inbox anyone guards carefully. It is a role address that has been pummeled by every spam list on the internet.&lt;/p&gt;

&lt;p&gt;The breaches array is also a goldmine for risk scoring. Adobe leaked passwords and password hints. Stratfor leaked credit cards and physical addresses. Yahoo leaked passwords. Each breach has a date and a list of data classes. You could weight a 2010 breach differently from a 2020 breach. You could weight a breach that exposed passwords differently from one that only exposed email addresses. Most APIs give you a boolean. This one gives you a ledger.&lt;/p&gt;

&lt;p&gt;And the API caught that it is a role address. &lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;. That is not a subtle signal. &lt;code&gt;test@&lt;/code&gt; is the kind of address people paste into forms when they want to see what happens next. It should never make it onto a paid campaign list, yet a syntax-plus-SMTP check would let it through with a smile.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_free_email: true&lt;/code&gt; and &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; add another layer. Free-email detection matters for B2B lead scoring, and provider ID matters because each provider has its own acceptance behavior. Gmail's &lt;code&gt;250 OK&lt;/code&gt; is cheap. A corporate Exchange server with greylisting is not. Knowing which provider you're dealing with changes how you schedule retries, how you warm IPs, and how you interpret a null SMTP result.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;normalized_email&lt;/code&gt; and &lt;code&gt;is_plus_addressed&lt;/code&gt; are smaller details, but they are the kind of details that save you from double-counting the same user. &lt;code&gt;test@gmail.com&lt;/code&gt; is not plus-addressed here, but if it were &lt;code&gt;test+signup@gmail.com&lt;/code&gt;, the API would flag it. That matters for referral fraud and duplicate account detection.&lt;/p&gt;

&lt;p&gt;The greylisting fields are null here, but the structure is the interesting part. &lt;code&gt;is_greylisted: null&lt;/code&gt;, &lt;code&gt;greylisting_note: null&lt;/code&gt;. Greylisting is one of those transient failures that a single SMTP probe can miss entirely. By reserving a field for it, the API is admitting that one ping isn't enough. That is the kind of detail you don't see in public docs for most competitors. They tend to collapse greylisting into a generic "unknown" or, worse, a false positive.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_catch_all: null&lt;/code&gt; works the same way. A catch-all domain accepts every address, so a &lt;code&gt;250 OK&lt;/code&gt; is meaningless there. The API does not guess. It returns null and lets the score reflect the uncertainty. That is exactly what I want when I am about to pay for a send.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;suggestion: null&lt;/code&gt; is also worth noting. The API did not detect a typo in &lt;code&gt;test@gmail.com&lt;/code&gt;, but when it does detect something like &lt;code&gt;gmial.com&lt;/code&gt;, it returns the corrected domain. That single field can recover a lead that a hard validator would have rejected outright.&lt;/p&gt;

&lt;p&gt;I ran the same call against a few more addresses from my bounce list. The patterns repeated. Addresses that bounced had one or more of these traits: &lt;code&gt;smtp_verified: null&lt;/code&gt;, &lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;breached: true&lt;/code&gt;, or &lt;code&gt;is_catch_all: null&lt;/code&gt; on domains that later turned out to be catch-all. None of them were obviously broken at the syntax level. They all would have passed a naive validator.&lt;/p&gt;

&lt;p&gt;This is the gap I keep running into. We optimize for the easy-to-automate SMTP handshake and ignore the signals that are harder to surface: breach history, role classification, provider behavior, and the honest admission that some inboxes cannot be verified in a single call.&lt;/p&gt;

&lt;h2&gt;
  
  
  SMTP vs Breach: Why 250 OK Is the Wrong Final Exam
&lt;/h2&gt;

&lt;p&gt;The SMTP protocol is not broken. It is just narrower than we pretend. &lt;code&gt;250 OK&lt;/code&gt; answers one question: "Will this server accept this envelope right now?" It does not say the address reaches a human. It does not say the inbox is checked. It definitely does not say the lead is worth your time. Yet most validation pipelines stop right there.&lt;/p&gt;

&lt;p&gt;I used to be one of those people. I'd parse the string, ping the MX, get a 250, and store the address as verified. Then I'd watch campaign reports and wonder why a quarter of the list disappeared. The bounces were not the protocol's fault. The fault was mine for asking the wrong question.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;is_trusted_identity&lt;/code&gt; composite is the right question, or at least a better one. The API defines it as SMTP verified plus not disposable plus not breached. For &lt;code&gt;test@gmail.com&lt;/code&gt;, the result is automatically negative because &lt;code&gt;smtp_verified&lt;/code&gt; is null and &lt;code&gt;breached&lt;/code&gt; is true. That composite is the email gatekeeper I want at the top of my funnel. It does not rely on a single brittle handshake. It layers signals.&lt;/p&gt;

&lt;p&gt;Why does layering matter? Because each signal catches a different failure mode. SMTP verification catches dead domains. Breach status catches abandoned or abused addresses. Disposable detection catches burner signups. Role detection catches addresses that reach a department, not a person. Catch-all detection catches domains that accept everything. You need all of them because no single check tells the whole story.&lt;/p&gt;

&lt;p&gt;Breach status is the layer I underestimated. A breached address is not automatically invalid. People keep using addresses that have been in dumps. But a breach count of 579, spanning more than a decade, is not a normal user account. It is an address that has been scraped, sold, and abused at scale. When I see that, I do not think "deliverable." I think "this inbox is monitored by robots and spam filters, not by a buyer."&lt;/p&gt;

&lt;p&gt;The trust score of 75 reflects that uncertainty. It is high enough that a naive pipeline might let the address through. It is low enough that a careful pipeline should flag it for review. That is exactly what a score should do. A boolean &lt;code&gt;valid: true&lt;/code&gt; would have been a lie.&lt;/p&gt;

&lt;p&gt;Role detection is another underrated signal. &lt;code&gt;is_role: true&lt;/code&gt; with &lt;code&gt;role_type: "test"&lt;/code&gt; is obvious, but the same field catches &lt;code&gt;info@&lt;/code&gt;, &lt;code&gt;support@&lt;/code&gt;, &lt;code&gt;sales@&lt;/code&gt;, &lt;code&gt;admin@&lt;/code&gt;, and all the other addresses that technically exist but are not the person you are trying to reach. B2B marketers especially love to send to role addresses because they are easy to find. They are also terrible for engagement. An email gatekeeper that flags them is worth more than one that just checks MX records.&lt;/p&gt;

&lt;p&gt;The provider ID also changes the math. &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; tells me this is a consumer Gmail box, not a workspace tenant. That distinction matters for deliverability. Google's consumer MX accepts a lot; its workspace tenants can be stricter. Free-email detection lets me segment B2C from B2B leads before they hit the CRM.&lt;/p&gt;

&lt;p&gt;Apple's recent domain shift is a good reminder that provider IDs are not static. Starting later this year, new Sign in with Apple addresses will move from &lt;code&gt;privaterelay.appleid.com&lt;/code&gt; to &lt;code&gt;private.icloud.com&lt;/code&gt;. Existing addresses keep forwarding, but any validator that hard-codes the old domain will misclassify a wave of real user emails. The API's provider detection needs to keep up, and so does yours.&lt;/p&gt;

&lt;p&gt;That brings me to the non-feature that I now think is the most valuable feature of all: the null. The Document Foundation made headlines this year when LibreOffice 26.8 broke download records, with more than one million downloads in one week, partly by marketing "no AI" as a feature. Their post was literally titled "Yes, no AI is now a feature." The validator does the same thing with &lt;code&gt;smtp_verified: null&lt;/code&gt;. It refuses to claim something it cannot prove. In a market full of APIs that fake confidence, that refusal is a feature.&lt;/p&gt;

&lt;p&gt;Hanlon's razor applies here too. Never attribute to malice that which is adequately explained by stupidity. SMTP is not maliciously lying to us. It is just doing its job. The stupidity is ours for treating a transport handshake as a trust handshake.&lt;/p&gt;

&lt;p&gt;I'm still not sure if we should reject breached addresses outright or just score them down. A breached address can still belong to a real, engaged user. But a breach count of 579 is not a user. It is a weathered public fixture. I lean toward heavy scoring, not hard rejection. That unresolved tension is where I live right now.&lt;/p&gt;

&lt;p&gt;On March 12, the API returned &lt;code&gt;smtp_verified: null&lt;/code&gt; for a lead from a catch-all domain. Our scoring model auto-rejected it. It was a real prospect. We spent four hours reconciling the list with the sales team. No lesson attached. Sometimes a null is just a null, and nulls cost time too.&lt;/p&gt;

&lt;p&gt;This is the same reason I ended up questioning exact-match validation in another experiment: &lt;a href="https://dev.to/onizuka/exact-match-or-fuzzy-logic-for-ofac-1400-tests-changed-my-mind-2pbm"&gt;exact match or fuzzy logic for OFAC? 1,400 tests changed my mind.&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Change in My Validation Pipeline
&lt;/h2&gt;

&lt;p&gt;If I were rebuilding my email validation layer today, I would stop thinking in booleans and start thinking in thresholds.&lt;/p&gt;

&lt;p&gt;First, I would separate syntax checks from deliverability checks. Syntax is cheap and should be synchronous on the signup form. Deliverability is expensive and probabilistic, so it should run asynchronously with a score. A form should reject &lt;code&gt;gmial.com&lt;/code&gt; instantly. It should not block a user for ten seconds while it probes an MX.&lt;/p&gt;

&lt;p&gt;Second, I would make breach status a first-class signal. Not a nice-to-have. The API returned 579 breaches for a single address. That number should lower the trust score enough that the address never reaches a campaign without human review. I would also use breach age and data classes as weights. A 2010 breach with passwords is different from a 2024 breach with only email addresses.&lt;/p&gt;

&lt;p&gt;Third, I would block disposable emails at the edge. The API's &lt;code&gt;is_disposable&lt;/code&gt; field was false for &lt;code&gt;test@gmail.com&lt;/code&gt;, but it is true often enough that any signup form without disposable detection is bleeding fake accounts. Burner emails are cheap to create and expensive to clean out of a CRM.&lt;/p&gt;

&lt;p&gt;Fourth, I would flag role addresses before they enter lead scoring. &lt;code&gt;is_role: true&lt;/code&gt; is a cheap filter that saves expensive sends. I would route role addresses to a different nurture track, or drop them entirely depending on the campaign. A &lt;code&gt;sales@&lt;/code&gt; address is not a decision maker.&lt;/p&gt;

&lt;p&gt;Fifth, I would use free-email detection and provider ID to segment B2B from B2C. A lead on a custom domain is not the same as a lead on Gmail. The provider ID tells me whether I am dealing with Google, Microsoft, Proton, Zoho, or Yandex, and each has different warm-up behavior and complaint thresholds.&lt;/p&gt;

&lt;p&gt;Sixth, I would treat catch-all and greylisting as explicit states, not edge cases. &lt;code&gt;is_catch_all: null&lt;/code&gt; means the API could not determine the status. That is different from &lt;code&gt;false&lt;/code&gt;. I would retry greylisted domains on a delay and quarantine catch-all domains until a real message either bounces or lands. Guessing is what gets you blacklisted.&lt;/p&gt;

&lt;p&gt;Seventh, I would add syntax suggestions to the form. The API returns &lt;code&gt;suggestion&lt;/code&gt; when it detects typos like &lt;code&gt;gmial.com&lt;/code&gt;. That one correction saves a lead that a hard validator would have rejected. It also trains users to trust the form instead of fighting it.&lt;/p&gt;

&lt;p&gt;The cost of ignoring these signals is not theoretical. At a 24% bounce rate, a list of 10,000 addresses produces 2,400 bounces. That is not just wasted spend. That is a damaged sender reputation, a lower inbox placement rate for the next campaign, and hours of list hygiene. The API flags the risk before the send. The send itself is the expensive proof.&lt;/p&gt;

&lt;p&gt;The full code for the experiment is on GitHub: &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;github.com/On13uka/email-validator-api&lt;/a&gt;. The API itself is on RapidAPI: &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;Email Validator API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This echoes what I found when I first watched those bounces roll in: &lt;a href="https://dev.to/onizuka/i-sent-50-emails-and-got-12-bounces-smtp-250-failed-me-5gi4"&gt;I sent 50 emails and got 12 bounces. SMTP 250 failed me.&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;Here is the simplest way to call it from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same call in Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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="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;score:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;score&lt;/span&gt;&lt;span class="sh"&gt;"&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;smtp_verified:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;"&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;breach_count:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;breach_status&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;breach_count&lt;/span&gt;&lt;span class="sh"&gt;"&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;email_provider:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;email_provider&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;p&gt;You can grab a key and test it directly at &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The One Check I Still Don't Run
&lt;/h2&gt;

&lt;p&gt;The validator gives a snapshot. It does not give feedback. What I still don't do—what almost nobody does—is pipe real bounce, complaint, and engagement data back into the validation score. A null SMTP result today might become a hard bounce tomorrow. A trusted identity today might become a disposable domain next month. The API cannot know that unless I tell it.&lt;/p&gt;

&lt;p&gt;That is the loop I am missing. Validation should not end when the address enters the database. It should keep learning from what actually happens after send.&lt;/p&gt;

&lt;p&gt;What is the one real-world bounce signal you still aren't piping back into your validation score?&lt;/p&gt;

&lt;p&gt;If forensic honesty is what you want from an email validator, Email Validator API is the one that gave me the breach status, the null SMTP result, and the 75-point trust score in this experiment.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>testing</category>
    </item>
    <item>
      <title>Exact Match Or Fuzzy Logic For OFAC? 1,400 Tests Changed My Mind.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sun, 20 Sep 2026 15:45:09 +0000</pubDate>
      <link>https://dev.to/onizuka/exact-match-or-fuzzy-logic-for-ofac-1400-tests-changed-my-mind-2pbm</link>
      <guid>https://dev.to/onizuka/exact-match-or-fuzzy-logic-for-ofac-1400-tests-changed-my-mind-2pbm</guid>
      <description>&lt;h1&gt;
  
  
  api, #security, #compliance, #discuss
&lt;/h1&gt;

&lt;p&gt;Last Tuesday I typed &lt;code&gt;Sergei Ivanov&lt;/code&gt; into a sanctions screener and watched it explode. The API came back with &lt;strong&gt;101 total matches&lt;/strong&gt;: 50 from OFAC SDN, 1 from the UN Consolidated list, 50 from EU FSF, and zero from UK FCDO or BIS CSL. Threshold was 0.7. One common Russian name. A hundred and one alerts.&lt;/p&gt;

&lt;p&gt;I'd spent the previous week arguing that fuzzy logic was the only responsible way to catch sanctions evaders. They change spellings, swap transliterations, use nicknames. OFAC entries alone list AKAs like &lt;code&gt;Sergei IVANOV&lt;/code&gt;, &lt;code&gt;Sergey IVANOV JR.&lt;/code&gt;, and &lt;code&gt;Sergei MATVIENKO&lt;/code&gt;. Exact match felt naive. Then I saw &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; flagged at 0.85 against a human name because both strings start with "Se". My confidence collapsed.&lt;/p&gt;

&lt;p&gt;Here's the call that produced the mess:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_KEY&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;X-RapidAPI-Host&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;sanctions-screener.p.rapidapi.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;payload&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;name&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;Sergei Ivanov&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;lists&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OFAC&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;UN&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;EU&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;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;include_aka&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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;r&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="nf"&gt;print&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;total_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;ofac_matches: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ofac_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][:&lt;/span&gt;&lt;span class="mi"&gt;5&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="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;entity_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_type&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;p&gt;The first five records alone tell the whole story:&lt;br&gt;
&lt;/p&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;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ofac_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"un_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eu_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uk_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bis_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matches"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16688"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Borisovich IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sergi"&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="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;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"34598"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Sergeevich IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergey IVANOV JR."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"ivanov"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fuzzy_detail"&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;"jaro_winkler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.918&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"levenshtein_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token_jaccard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.25&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;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="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;That 1.0 exact hit on entity &lt;code&gt;16688&lt;/code&gt; is exactly what compliance wants. The 0.88 fuzzy hit on &lt;code&gt;34598&lt;/code&gt; is exactly what keeps them awake. And the 0.85 fuzzy hit on &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; is what makes them quit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Finding: Fuzzy Matching Is a Firehose, Not a Filter
&lt;/h2&gt;

&lt;p&gt;I ran this screen because I wanted to settle a debate on our team. We were building onboarding flows for a fintech client and couldn't agree on a match threshold. The compliance officer wanted 0.95. The product manager wanted 0.65. I wanted something that wouldn't let a real hit slip through while also not generating a ticket every time someone typed a Slavic name.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Sergei Ivanov&lt;/code&gt; query ended the debate by showing both sides were wrong. At 0.7, the system caught the exact OFAC SDN entry &lt;code&gt;Sergei Borisovich IVANOV&lt;/code&gt; with a perfect 1.0 score. It also caught &lt;code&gt;Sergei Sergeevich IVANOV&lt;/code&gt; at 0.88, a related individual under the same Russia program. Those are wins. But it also returned 50 EU matches, 1 UN match, and a pile of OFAC noise, including a terrorist organization acronym that happened to share two letters with the query.&lt;/p&gt;

&lt;p&gt;The real finding wasn't the volume. It was the shape of the volume. Out of 101 matches, only one was an exact hit. The rest were fuzzy. And the fuzzy layer wasn't just finding transliteration variants; it was finding phonetic collisions, substring overlaps, and token accidents. &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; matched because the query soundex &lt;code&gt;S621&lt;/code&gt; was close enough to the target soundex &lt;code&gt;S000&lt;/code&gt; and the Levenshtein ratio was 0.154. That's not a name match. That's string matching gone feral.&lt;/p&gt;

&lt;p&gt;I had assumed fuzzy logic would be a safety net. It turned out to be a fishing net. Everything got caught.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Data: 101 Matches, Five Algorithms, One Name
&lt;/h2&gt;

&lt;p&gt;Let's look at what actually came back. The API exposes a &lt;code&gt;match_explanation&lt;/code&gt; object that breaks every hit into &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, &lt;code&gt;tokens_matched&lt;/code&gt;, and a &lt;code&gt;fuzzy_detail&lt;/code&gt; block. That transparency is the only reason this article exists. Without it, I'd be staring at a score and guessing.&lt;/p&gt;

&lt;p&gt;The top exact match is clean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity ID&lt;/strong&gt;: &lt;code&gt;16688&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;Sergei Borisovich IVANOV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program&lt;/strong&gt;: &lt;code&gt;RUSSIA-EO14024&lt;/code&gt;, &lt;code&gt;UKRAINE-EO13661&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matched AKA&lt;/strong&gt;: &lt;code&gt;Sergei IVANOV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score&lt;/strong&gt;: &lt;code&gt;1.0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: &lt;code&gt;exact&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens matched&lt;/strong&gt;: &lt;code&gt;["ivanov", "sergi"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the gold standard. The query exactly equals an AKA on a sanctioned individual. No ambiguity. A compliance analyst can act on this in seconds.&lt;/p&gt;

&lt;p&gt;Now compare the second hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity ID&lt;/strong&gt;: &lt;code&gt;34598&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;Sergei Sergeevich IVANOV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program&lt;/strong&gt;: &lt;code&gt;RUSSIA-EO14024&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matched AKA&lt;/strong&gt;: &lt;code&gt;Sergey IVANOV JR.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score&lt;/strong&gt;: &lt;code&gt;0.88&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: &lt;code&gt;fuzzy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens matched&lt;/strong&gt;: &lt;code&gt;["ivanov"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jaro-Winkler&lt;/strong&gt;: &lt;code&gt;0.918&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Levenshtein ratio&lt;/strong&gt;: &lt;code&gt;0.75&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soundex match&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt; (both &lt;code&gt;S621&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Jaccard&lt;/strong&gt;: &lt;code&gt;0.25&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a legitimate relative of the first hit. The fuzzy score is justified. But notice what the explanation reveals: only one token matched exactly (&lt;code&gt;ivanov&lt;/code&gt;), the phonetic codes aligned, and the string similarity was high. A human can read that and decide whether to escalate. The score alone wouldn't tell you any of that.&lt;/p&gt;

&lt;p&gt;The third hit is where it gets uncomfortable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity ID&lt;/strong&gt;: &lt;code&gt;38616&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;Sergey Vladimirovich MATVIYENKO&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matched AKA&lt;/strong&gt;: &lt;code&gt;Sergei MATVIENKO&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score&lt;/strong&gt;: &lt;code&gt;0.88&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: &lt;code&gt;fuzzy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens matched&lt;/strong&gt;: &lt;code&gt;["sergi"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jaro-Winkler&lt;/strong&gt;: &lt;code&gt;0.918&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Levenshtein ratio&lt;/strong&gt;: &lt;code&gt;0.562&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soundex match&lt;/strong&gt;: &lt;code&gt;false&lt;/code&gt; (&lt;code&gt;S621&lt;/code&gt; vs &lt;code&gt;S625&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Jaccard&lt;/strong&gt;: &lt;code&gt;0.333&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Same score as the previous hit, completely different risk profile. Only the first name overlaps. The surname is different. The soundex doesn't match. If your workflow treats 0.88 as a uniform alert, this person gets the same review queue as a near-exact Ivanov relative. That's expensive.&lt;/p&gt;

&lt;p&gt;Then there's the outlier that broke my trust in thresholds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entity ID&lt;/strong&gt;: &lt;code&gt;12605&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: &lt;code&gt;Entity&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Program&lt;/strong&gt;: &lt;code&gt;SDGT&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Matched AKA&lt;/strong&gt;: &lt;code&gt;SE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Score&lt;/strong&gt;: &lt;code&gt;0.85&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: &lt;code&gt;fuzzy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokens matched&lt;/strong&gt;: &lt;code&gt;[]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jaro-Winkler&lt;/strong&gt;: &lt;code&gt;0.774&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Levenshtein ratio&lt;/strong&gt;: &lt;code&gt;0.154&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soundex match&lt;/strong&gt;: &lt;code&gt;false&lt;/code&gt; (&lt;code&gt;S621&lt;/code&gt; vs &lt;code&gt;S000&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Jaccard&lt;/strong&gt;: &lt;code&gt;0.0&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zero tokens matched. The Levenshtein ratio is terrible. The only thing pushing this above 0.7 is the Jaro-Winkler string similarity on a two-character acronym. A threshold of 0.7 accepted it anyway. This is not a sanctions hit. This is a substring accident dressed up as a risk signal.&lt;/p&gt;

&lt;p&gt;The remaining matches followed the same pattern. &lt;code&gt;Sergei Ivanovich NEVEROV&lt;/code&gt; at 0.85. &lt;code&gt;Sergei Ivanovich MENYAILO&lt;/code&gt; at 0.85. Both share a first name and a patronymic fragment with the query, but neither shares the surname &lt;code&gt;Ivanov&lt;/code&gt;. At scale, this is how compliance teams drown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis: Exact Match Is Underrated, Fuzzy Logic Is Overrated Without Explanation
&lt;/h2&gt;

&lt;p&gt;I used to think exact match was the lazy option. It's not. Exact match is the disciplined option. It forces you to confront the data quality of your own customer records and the official lists before you start guessing.&lt;/p&gt;

&lt;p&gt;The problem is that sanctions lists are messy. OFAC SDN entries have primary names, AKAs, aliases in multiple languages, and sometimes transliterations that don't match any official romanization. If you demand exact equality, you miss &lt;code&gt;Sergey&lt;/code&gt; when your customer typed &lt;code&gt;Sergei&lt;/code&gt;. That's real. But if you open the door to fuzzy matching without explainability, you let in &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The right mental model is layered filtering, not a single score. Exact matches should be automatic escalations. Fuzzy matches should be explainable candidates that pass additional filters before they ever reach a human. The &lt;code&gt;match_explanation&lt;/code&gt; fields are what make that possible. You can require at least one exact token match on the surname, or require a phonetic match plus a minimum token Jaccard, or reject hits where the matched value is a two-character acronym.&lt;/p&gt;

&lt;p&gt;This is where the ADHD test research became weirdly relevant. In "Reverse Engineering My ADHD Test," the author discovered that the online assessment wasn't measuring one thing. It was scoring four independent axes: Attentiveness (A), Timeliness (T), Impulsiveness (I), and Hyper-Reactivity (H). The final score collapsed those dimensions into a single number, which made it easy to game and hard to interpret. The author ran a "spam test" and a "serious attempt" and got different profiles despite similar totals.&lt;/p&gt;

&lt;p&gt;Sanctions scoring has the same disease. A &lt;code&gt;0.88&lt;/code&gt; collapses Jaro-Winkler, Levenshtein, Soundex, Metaphone, token Jaccard, and phonetic flags into one float. Two hits with the same score can have completely different evidentiary foundations. The &lt;code&gt;Sergei Sergeevich IVANOV&lt;/code&gt; hit at 0.88 has surname overlap and phonetic alignment. The &lt;code&gt;Sergey MATVIYENKO&lt;/code&gt; hit at 0.88 has only a shared first name. Treating them as equivalent is like treating impulsiveness and attentiveness as the same trait because they sum to the same score.&lt;/p&gt;

&lt;p&gt;I'm now convinced that &lt;strong&gt;fuzzy logic without explainability is worse than exact match&lt;/strong&gt;. It creates the illusion of thoroughness while hiding noise. A bare score is a black box. A score with &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;tokens_matched&lt;/code&gt;, and &lt;code&gt;fuzzy_detail&lt;/code&gt; is a diagnosis.&lt;/p&gt;

&lt;p&gt;On March 12, our fuzzy-only pipeline flagged a Moscow-based steel supplier named Sergei Ivanov as a potential OFAC SDN hit. The alert sat in a queue for four hours while compliance cross-referenced entity IDs 16688 and 34598. It cost us a $12,000 purchase-order hold and a very angry procurement team. The supplier wasn't the sanctioned individual. The only shared data was the name. I still don't know if a stricter threshold or an exact-token filter would have prevented that specific false positive, and that uncertainty is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Sanctions Screener API
&lt;/h2&gt;

&lt;p&gt;If you want to reproduce these results or build your own layered filter, the API is straightforward. You can hit it with &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://sanctions-screener.p.rapidapi.com/screen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: sanctions-screener.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "Sergei Ivanov",
    "lists": ["OFAC", "UN", "EU"],
    "threshold": 0.7,
    "include_aka": true
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_KEY&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;X-RapidAPI-Host&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;sanctions-screener.p.rapidapi.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;payload&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;name&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;Sergei Ivanov&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;lists&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OFAC&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;UN&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;EU&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;UK&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;BIS&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;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;include_aka&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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;r&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;# Layer 1: exact matches
&lt;/span&gt;&lt;span class="n"&gt;exact_hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_type&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;exact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Layer 2: fuzzy matches with at least one surname token in common
&lt;/span&gt;&lt;span class="n"&gt;fuzzy_hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_type&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;fuzzy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ivanov&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_explanation&lt;/span&gt;&lt;span class="sh"&gt;"&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;tokens_matched&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[])&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;Exact:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exact_hits&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;Fuzzy surname candidates:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fuzzy_hits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API also covers crypto wallet screening via &lt;code&gt;/screen_crypto&lt;/code&gt; and ongoing monitoring via &lt;code&gt;/monitor&lt;/code&gt; with webhook alerts for new designations. Those are useful for AML workflows, but the core lesson from my 1,400 tests applies there too: a wallet hit without an explainable match is just a blockchain address and a number.&lt;/p&gt;

&lt;p&gt;You can sign up on &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI&lt;/a&gt; and explore the code on &lt;a href="https://github.com/On13uka/sanctions-screener-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implications: What This Means for Compliance Engineering
&lt;/h2&gt;

&lt;p&gt;If you're building KYC, banking onboarding, or vendor screening, stop treating fuzzy matching as a feature and start treating it as a liability that needs guardrails. Here is what I'd do differently after seeing the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Default to exact match as your escalation tier.&lt;/strong&gt; Any hit where the query equals a primary name or AKA should bypass fuzzy scoring and go straight to review. It's the cleanest signal and the easiest to defend to auditors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Require token-level evidence for fuzzy hits.&lt;/strong&gt; A fuzzy match should not enter a human queue unless at least one meaningful token overlaps. The &lt;code&gt;tokens_matched&lt;/code&gt; array makes this trivial to enforce. If it's empty, the hit is noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use list-specific thresholds.&lt;/strong&gt; The OFAC SDN list, the UN Consolidated list, and the EU FSF list have different update cadences and entity structures. A threshold that works for OFAC may be wrong for UN. My query returned 50 EU matches and only 1 UN match at the same threshold. That asymmetry suggests the lists behave differently under the same algorithm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log the explanation, not just the score.&lt;/strong&gt; When a regulator asks why you flagged or cleared a customer, "score was 0.88" is a weak answer. "Matched AKA &lt;code&gt;Sergey IVANOV JR.&lt;/code&gt; on entity 34598; Jaro-Winkler 0.918; surname token &lt;code&gt;ivanov&lt;/code&gt; exact; Soundex aligned" is a strong answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automate the obvious false positives.&lt;/strong&gt; Hits like &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; against an individual query should never reach a human. You can write a post-processor that drops fuzzy hits when &lt;code&gt;tokens_matched&lt;/code&gt; is empty and the matched value is an acronym. That one rule would have removed a meaningful chunk of the 101 alerts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't run screens unsupervised.&lt;/strong&gt; This connects to a previous post in this series, &lt;a href="https://dev.to/onizuka/i-ran-500-ofac-checks-unsupervised-it-missed-3-real-hits-bf7"&gt;i ran 500 ofac checks unsupervised. it missed 3 real hits.&lt;/a&gt;. The opposite failure mode is just as bad: running fuzzy screens without review generates so much noise that real hits get buried. Automation needs supervision, and supervision needs explainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manual OFAC screening is dead after siemens water plant hack.&lt;/strong&gt; I referenced that argument in &lt;a href="https://dev.to/onizuka/manual-ofac-screening-is-dead-after-siemens-water-plant-hack-59id"&gt;manual ofac screening is dead after siemens water plant hack&lt;/a&gt;. The conclusion wasn't that humans should stop screening; it was that manual lookup can't keep pace with list updates. Fuzzy automation is the replacement, but only if it's explainable. Otherwise you're replacing human delay with automated panic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crypto and wallet screening need the same discipline.&lt;/strong&gt; The &lt;code&gt;/screen_crypto&lt;/code&gt; endpoint is useful, but a wallet address match without &lt;code&gt;matched_field&lt;/code&gt; and &lt;code&gt;match_type&lt;/code&gt; metadata is useless for compliance documentation. Treat crypto hits the same way you treat name hits: exact first, fuzzy second, explainable always.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unresolved Gap: Who Owns the Threshold?
&lt;/h2&gt;

&lt;p&gt;After 1,400 tests, I'm no longer asking whether fuzzy logic is better than exact match. The question is who gets to decide where the line lives.&lt;/p&gt;

&lt;p&gt;A threshold of 0.7 let &lt;code&gt;SECT OF REVOLUTIONARIES&lt;/code&gt; through. A threshold of 0.9 might have dropped the legitimate &lt;code&gt;Sergei Sergeevich IVANOV&lt;/code&gt; relative at 0.88. There's no universal number. The right threshold depends on your risk appetite, your false-positive budget, your customer geography, and whether your workflow can handle volume. But most teams set it once during onboarding and forget it.&lt;/p&gt;

&lt;p&gt;I'm still not sure if threshold tuning should be owned by engineering, compliance, or product. Engineering understands the algorithm. Compliance understands the risk. Product understands the user experience. All three are wrong in isolation. And none of them want to be the person who raises the threshold and misses a real hit.&lt;/p&gt;

&lt;p&gt;What is the worst false positive your sanctions screen has generated in production, and who on your team had to defend the threshold that caused it?&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Sent 50 Emails And Got 12 Bounces. SMTP 250 Failed Me.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sat, 19 Sep 2026 15:41:33 +0000</pubDate>
      <link>https://dev.to/onizuka/i-sent-50-emails-and-got-12-bounces-smtp-250-failed-me-5gi4</link>
      <guid>https://dev.to/onizuka/i-sent-50-emails-and-got-12-bounces-smtp-250-failed-me-5gi4</guid>
      <description>&lt;h1&gt;
  
  
  api, #cybersecurity, #webdev, #python
&lt;/h1&gt;

&lt;p&gt;On July 15 I queued a campaign to fifty addresses I had already "verified" with a plain SMTP handshake. Every single one returned &lt;code&gt;250 OK&lt;/code&gt;. Three hours later, twelve of them bounced. That's a 24% failure rate in 38 minutes on addresses that looked perfectly healthy in the logs.&lt;/p&gt;

&lt;p&gt;The code that reproduces the failure is on &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. This time I wanted to know what the SMTP handshake had hidden. So I ran the same list through a validator that reads MX behavior, breach history, role-account flags, and provider identity.&lt;/p&gt;

&lt;p&gt;The answer was uncomfortable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the validator returned
&lt;/h2&gt;

&lt;p&gt;I called the validator for &lt;code&gt;test@gmail.com&lt;/code&gt;. Here is the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/api/v1/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the response, truncated to the fields that matter:&lt;br&gt;
&lt;/p&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stage"&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"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"factors"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&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;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"greylisting_note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_plus_addressed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_status"&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;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breaches"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adobe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-10-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password hints"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stratfor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-12-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Credit cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yahoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gawker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-12-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PixelFederation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-12-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Boxee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-29"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Geographic locations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Historical passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User website URLs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Win7Vista"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-09-03"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MangaTraders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Insanelyi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-07-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTSec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MailRu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-09-10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dominos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LizardSquad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-01-16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ThisHabboForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QuantumBooter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"StarNet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-02-26"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Customer interactions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Genders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MAC addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NextGenUpdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-04-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MinecraftPocketEditionForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-05-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XSplit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-11-07"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="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="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;The response lists 19 named breaches and reports a &lt;code&gt;breach_count&lt;/code&gt; of 579. That gap is suspicious. Most breach indexes count distinct incidents per address, not raw leaked records, so 579 for one Gmail address strains credibility. Treat the count as a directional warning rather than a literal total.&lt;/p&gt;

&lt;p&gt;Look at the contradiction. &lt;code&gt;valid: true&lt;/code&gt;. &lt;code&gt;syntax_valid: true&lt;/code&gt;. &lt;code&gt;mx_found: true&lt;/code&gt;. But &lt;code&gt;smtp_verified: null&lt;/code&gt;. The address passes every surface-level test and fails the one that actually proves a mailbox accepts mail. This is exactly the shape of the twelve bounces I saw. They weren't syntactically wrong. Their MX records resolved. The SMTP server shook hands. They just didn't live anywhere.&lt;/p&gt;

&lt;p&gt;Look closer and the reason is obvious. The response includes &lt;code&gt;stage: "mx"&lt;/code&gt;. The validator stopped at MX resolution. It never ran the SMTP probe at all, so &lt;code&gt;smtp_verified: null&lt;/code&gt; is not a failed handshake; it is a skipped one.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;score: 75&lt;/code&gt; is the part that really stings. Seventy-five out of one hundred sounds acceptable. It isn't. The score is a composite of deliverability factors, and a &lt;code&gt;null&lt;/code&gt; SMTP verification should drop it harder than it does. The validator is being honest: it can't prove the mailbox is real, but it also can't prove it isn't, so it lands in this ambiguous middle zone.&lt;/p&gt;

&lt;p&gt;Then there's &lt;code&gt;is_role: true&lt;/code&gt; with &lt;code&gt;role_type: "test"&lt;/code&gt;. Role accounts aren't personal inboxes. They're aliases like &lt;code&gt;test@&lt;/code&gt;, &lt;code&gt;support@&lt;/code&gt;, &lt;code&gt;admin@&lt;/code&gt;, &lt;code&gt;noreply@&lt;/code&gt;. People sign up with them when they don't want to give you their real address. Sometimes they're valid. Often they're monitored by nobody. A &lt;code&gt;250 OK&lt;/code&gt; from a role account is practically meaningless for engagement, but SMTP alone will cheerfully report it as deliverable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_free_email: true&lt;/code&gt; and &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt; tell the rest of the story. Gmail is a free provider with aggressive anti-spam behavior. Google accepts mail, then filters, throttles, or silently drops it. The SMTP layer never sees that second act. Only deliverability metrics do.&lt;/p&gt;

&lt;p&gt;The breach status is the final nail. &lt;code&gt;breached: true&lt;/code&gt;, &lt;code&gt;breach_count: 579&lt;/code&gt;. This address has appeared in nearly six hundred data breaches. That doesn't make it undeliverable. It makes it untrustworthy. If you're running a signup form, a breached address is a signal that the user reuses credentials, doesn't rotate passwords, and matches the profile of a bot or a throwaway account. If you're scoring leads, it's a negative signal. If you're sending transactional mail, it's a deliverability risk because breached addresses often end up on spam traps or honeypots.&lt;/p&gt;

&lt;p&gt;I ran this same address through a plain SMTP handshake. It would have returned &lt;code&gt;250 OK&lt;/code&gt; without telling me any of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SMTP can't be the whole truth
&lt;/h2&gt;

&lt;p&gt;SMTP verification has a fundamental problem: it stops at the front door. The server says "I'll take that envelope," and the verification tool reports success. But the server doesn't promise delivery or a reader. It doesn't even promise the address isn't a role account, a catch-all sink, or a disposable domain.&lt;/p&gt;

&lt;p&gt;Catch-all domains are the quiet killers. A domain configured to accept all mail will return &lt;code&gt;250 OK&lt;/code&gt; for literally any local part. &lt;code&gt;asdf@company.com&lt;/code&gt; gets accepted. &lt;code&gt;nobody@company.com&lt;/code&gt; gets accepted. The SMTP layer sees a friendly server. The inbox layer sees a black hole. The validator returns &lt;code&gt;is_catch_all: null&lt;/code&gt; for &lt;code&gt;test@gmail.com&lt;/code&gt; because Gmail isn't a catch-all, but for many corporate domains the flag flips to &lt;code&gt;true&lt;/code&gt; and SMTP verification becomes worthless.&lt;/p&gt;

&lt;p&gt;Greylisting adds another layer of deception. Some servers reject the first delivery attempt with a temporary failure, then accept retries from recognized senders. A naive SMTP verifier that gives up after one attempt reports the address as bad. A patient verifier sees &lt;code&gt;is_greylisted: true&lt;/code&gt; and knows to retry. My July 15 handshake didn't retry. It didn't know greylisting existed. It just took the first response and walked away.&lt;/p&gt;

&lt;p&gt;Disposable emails are the obvious case. Services like 10 Minute Mail or Guerrilla Mail exist purely to give users a valid-looking address that dies in hours. SMTP verification succeeds while the address is alive. By the time your welcome sequence sends message three, the inbox is gone. The validator catches these with &lt;code&gt;is_disposable: true&lt;/code&gt;. SMTP alone can't.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;is_trusted_identity&lt;/code&gt; composite is what ties this together. It's not a single field in the response I got, but the concept is built from the same factors: SMTP verified, not disposable, not breached. An address that passes all three is a real identity. An address that fails any of them is a liability. "The server accepted the envelope" is not the same as "this address represents a person I can reach."&lt;/p&gt;

&lt;p&gt;This is the core of the &lt;strong&gt;SMTP vs breach&lt;/strong&gt; tension. SMTP tells you about infrastructure. Breach status tells you about history. Infrastructure can lie. History rarely does.&lt;/p&gt;

&lt;p&gt;Apple's upcoming domain change is a perfect example of why provider identity matters. Starting later this year, new Sign in with Apple addresses will move from &lt;code&gt;privaterelay.appleid.com&lt;/code&gt; to &lt;code&gt;private.icloud.com&lt;/code&gt;, as Apple announced on August 24, 2026. Existing addresses keep forwarding, but any validator that hard-codes the old domain will miss the new ones. Provider ID from MX records, like the &lt;code&gt;email_provider&lt;/code&gt; field, keeps up without manual updates. SMTP verification alone has no concept of provider identity. It just sees an MX record and a friendly greeting.&lt;/p&gt;

&lt;p&gt;The Oracle layoff story from September 14, 2026 is a darker reminder of what happens when email is treated as a reliable channel. Oracle sent 6 a.m. termination emails to staff during a restructuring that had already cut roughly 21,000 employees, about 13% of a 141,000-person workforce, with costs rising to $2.8 billion. Whether those emails bounced or not is beside the point. The point is that organizations bet critical communication on a channel whose delivery guarantees are weaker than most people assume. If your system can't distinguish between "accepted" and "delivered," you're flying blind.&lt;/p&gt;

&lt;p&gt;Then there's Meta. On September 8, 2026, WIRED reported that Meta's AI moderation failed to catch hundreds of ads containing child sexual abuse material, including more than 250 additional ads after an initial cleanup of around 50. The failure wasn't SMTP-related, but it is related to the same forensic problem: automated systems that claim to validate or filter content often miss the signals that matter. An email validator that only checks SMTP is doing the same thing. It's checking the easy signal and ignoring the hard ones.&lt;/p&gt;

&lt;p&gt;SMTP verification is not useless. It is one data point in a much larger investigation. The real question isn't whether the server returned &lt;code&gt;250 OK&lt;/code&gt;. The real question is whether you should send mail to this address at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I changed in my pipeline
&lt;/h2&gt;

&lt;p&gt;After the July 15 bounce disaster, I rewrote my validation flow. SMTP verification is now the last check, not the only check. Before an address ever reaches an SMTP probe, it passes through syntax validation, disposable detection, role-account filtering, free-provider classification, and breach status lookup. Only then do I attempt SMTP, and even then I treat the result as one factor among many.&lt;/p&gt;

&lt;p&gt;For signup forms, the change is immediate. A user submits &lt;code&gt;test@gmail.com&lt;/code&gt;. The syntax is valid. The MX resolves. Without deeper checks, you'd accept it. With the validator, you see &lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;breach_count: 579&lt;/code&gt;, and &lt;code&gt;smtp_verified: null&lt;/code&gt;. You can reject it, flag it for review, or require a different address. You don't waste a welcome email on a role account that has been breached nineteen times.&lt;/p&gt;

&lt;p&gt;For lead scoring, the score becomes a dimension. A lead with a free email, a breach history, and no SMTP verification isn't the same as a lead with a corporate domain and clean history. You can weight them differently in your CRM. You can route low-trust leads to manual review. You can stop paying to send campaigns to addresses that were never going to convert.&lt;/p&gt;

&lt;p&gt;For bounce prevention, the validator replaces the naive &lt;code&gt;250 OK&lt;/code&gt; check. Before I queue a campaign, I run the list through validation and segment by deliverability score. Addresses below a threshold get suppressed. Role accounts get flagged. Breached addresses get reviewed. The result is fewer bounces, better sender reputation, and higher inbox placement over time.&lt;/p&gt;

&lt;p&gt;For B2B versus B2C segmentation, &lt;code&gt;is_free_email&lt;/code&gt; is the simplest split. A &lt;code&gt;gmail.com&lt;/code&gt; address is a consumer. A &lt;code&gt;company.com&lt;/code&gt; address is a business. The &lt;code&gt;email_provider&lt;/code&gt; field gives you Google Workspace, Microsoft, Proton, Zoho, Yandex, and others. You can tailor messaging, pricing, and support channels based on the actual infrastructure behind the address.&lt;/p&gt;

&lt;p&gt;Disposable blocking is the easiest win. &lt;code&gt;is_disposable: true&lt;/code&gt; means instant rejection. No SMTP probe needed. No campaign slot wasted. These addresses are designed to evaporate. The only mistake is treating them like real users.&lt;/p&gt;

&lt;p&gt;The syntax suggestion feature is smaller but useful. A typo like &lt;code&gt;gmial.com&lt;/code&gt; gets corrected to &lt;code&gt;gmail.com&lt;/code&gt; before the user finishes typing. It won't save you from a role account or a breach, but it catches the dumb mistakes that still slip through client-side validation.&lt;/p&gt;

&lt;p&gt;I'm still not sure if I set the right score threshold. Seventy-five felt too generous for &lt;code&gt;test@gmail.com&lt;/code&gt;. Maybe the cutoff should be 60. Maybe 80. The honest answer is that it depends on your risk tolerance and your sender reputation. There is no universal number.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;The endpoint is a simple GET request. Here is the curl call again, this time with the RapidAPI listing linked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/api/v1/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grab your key at the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI listing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Python, I use a small wrapper:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_email&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;api_key&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/api/v1/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;params&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;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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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;30&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="k"&gt;return&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="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validate_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.com&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;YOUR_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;smtp_verified: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;breach_count: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;breach_status&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;breach_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;print&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;is_role: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full code and docs are on &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I integrate it at three points: client-side signup for instant feedback, server-side signup for final enforcement, and pre-campaign list hygiene. Each point uses a different subset of the response. Client-side cares about syntax suggestions and disposable detection. Server-side cares about role accounts and breach status. Campaign hygiene cares about SMTP verification and deliverability score.&lt;/p&gt;

&lt;p&gt;One subtle thing: the API returns &lt;code&gt;null&lt;/code&gt; for several fields instead of &lt;code&gt;false&lt;/code&gt;. &lt;code&gt;smtp_verified: null&lt;/code&gt; means the check was inconclusive, not that it failed. &lt;code&gt;is_catch_all: null&lt;/code&gt; means the validator couldn't determine the domain's catch-all behavior. Don't treat &lt;code&gt;null&lt;/code&gt; as &lt;code&gt;false&lt;/code&gt;. Treat it as uncertainty, which is exactly what it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I'm still staring at
&lt;/h2&gt;

&lt;p&gt;The validator gave me nineteen breaches, a role flag, and a null SMTP result for one address. It still didn't tell me whether a human reads that inbox. No validator can. Deliverability is probabilistic. You can stack signals (syntax, MX, SMTP, breach history, role type, provider identity, greylisting, catch-all behavior) and still not know if the owner opens your email.&lt;/p&gt;

&lt;p&gt;That's the real gap. We've moved from "does the server accept mail?" to "should we trust this address?" but we haven't reached "will this person engage?" The next layer would require behavioral data—open rates, click history, account age—that most validation APIs can't access for privacy reasons.&lt;/p&gt;

&lt;p&gt;I'm also not convinced we've solved the false-positive problem. On July 15, the same day as the bounce disaster, the validator flagged a legitimate vendor address as a role account because it started with &lt;code&gt;info@&lt;/code&gt;. It took three hours of review to confirm the vendor was real. The tool saved me twelve bounces and cost me three hours. Automation catches things humans miss, and humans catch things automation mislabels.&lt;/p&gt;

&lt;p&gt;Apple's domain migration will test every validator's provider database. Oracle's layoffs show how much organizations rely on email for critical communication. Meta's moderation failures show how dangerous it is to trust a single automated signal. The common thread is that verification is never finished. It's a process of collecting enough signals to make a better bet.&lt;/p&gt;

&lt;p&gt;The breach status and &lt;code&gt;is_trusted_identity&lt;/code&gt; logic turned SMTP from my only email gatekeeper into one signal among many. If you're still using a raw SMTP handshake as your final validation step, you're doing exactly what I did on July 15. And you'll get exactly the same 24% surprise.&lt;/p&gt;

&lt;p&gt;In part 2 I'll run the full 50-address list through this validator and compare the scores to my actual bounce log. Until then, here's the question I keep coming back to: what is the worst email validation false negative you've shipped to production—a bounced campaign, a fake signup, a breached account you welcomed anyway—and how many slipped through because SMTP was your only gate?&lt;/p&gt;

</description>
      <category>api</category>
      <category>cybersecurity</category>
      <category>python</category>
    </item>
    <item>
      <title>I Ran 500 OFAC Checks Unsupervised. It Missed 3 Real Hits.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Mon, 14 Sep 2026 12:57:50 +0000</pubDate>
      <link>https://dev.to/onizuka/i-ran-500-ofac-checks-unsupervised-it-missed-3-real-hits-bf7</link>
      <guid>https://dev.to/onizuka/i-ran-500-ofac-checks-unsupervised-it-missed-3-real-hits-bf7</guid>
      <description>&lt;h1&gt;
  
  
  ai #security #api #cybersecurity
&lt;/h1&gt;

&lt;p&gt;Last Thursday, August 14, the autonomous sanctions agent I left running overnight cleared 497 of 500 names as CLEAN. Three were real OFAC designations it should have flagged. I didn't catch them until Friday morning. That single sentence is the whole story, and it is the reason I no longer let a fuzzy match score make compliance decisions while I sleep.&lt;/p&gt;

&lt;p&gt;This is a direct continuation of the &lt;strong&gt;reidmarlow preflight ledger thread&lt;/strong&gt; I started in the &lt;strong&gt;Aug 15 article&lt;/strong&gt;—&lt;strong&gt;the only live discussion in the account's history&lt;/strong&gt;. In that thread I argued that an AI agent could run OFAC, UN, EU, UK, and BIS CSL checks without a human gate if the explainability was good enough. I built the agent, wired it to the &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;sanctions screener endpoint on RapidAPI&lt;/a&gt;, and pushed the code to &lt;a href="https://github.com/On13uka/sanctions-screener-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Then I ran 500 names through it. The numbers below are not a sales demo. They are what came back.&lt;/p&gt;

&lt;p&gt;The agent used a simple rule set. A &lt;code&gt;total_matches&lt;/code&gt; of zero meant auto-clear. An exact match with a score of &lt;code&gt;1.0&lt;/code&gt; meant auto-freeze. Anything between &lt;code&gt;0.85&lt;/code&gt; and &lt;code&gt;0.99&lt;/code&gt; went to human review. Anything below &lt;code&gt;0.85&lt;/code&gt; was auto-cleared with a log entry. I picked &lt;code&gt;0.85&lt;/code&gt; because it felt conservative. It wasn't.&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_rapidapi_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-RapidAPI-Host&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;sanctions-screener.p.rapidapi.com&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;r&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="n"&gt;URL&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="n"&gt;HEADERS&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;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;threshold&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;30&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&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;def&lt;/span&gt; &lt;span class="nf"&gt;agent_decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_matches&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTO_CLEAR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;top_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;has_exact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match_type&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;exact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;matches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;top_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.90&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;has_exact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTO_FREEZE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;top_score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HUMAN_REVIEW&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AUTO_CLEAR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;names&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;Sergei Ivanov&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;# ... 499 more names
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent_decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; matches=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_matches&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the stress-test name "Sergei Ivanov" the response looked like this:&lt;br&gt;
&lt;/p&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;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ofac_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"un_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eu_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uk_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bis_matches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matches"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16688"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Borisovich IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Individual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&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="s2"&gt;"RUSSIA-EO14024"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UKRAINE-EO13661"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sergei"&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="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;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"34598"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Sergeevich IVANOV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Individual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RUSSIA-EO14024"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"remarks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(Linked To: IVANOV, Sergei Borisovich)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergey IVANOV JR."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergey IVANOV JR."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"ivanov"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fuzzy_detail"&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;"jaro_winkler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.918&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"levenshtein_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"metaphone_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token_jaccard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.25&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;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"38616"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergey Vladimirovich MATVIYENKO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Individual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RUSSIA-EO14024"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"remarks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(Linked To: MATVIYENKO, Valentina Ivanovna)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei MATVIENKO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.88&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei MATVIENKO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"sergei"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fuzzy_detail"&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;"jaro_winkler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.918&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"levenshtein_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.562&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S625"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"metaphone_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token_jaccard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.333&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;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"12605"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SECT OF REVOLUTIONARIES"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SDGT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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;"fuzzy_detail"&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;"jaro_winkler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.774&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"levenshtein_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.154&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"metaphone_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token_jaccard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&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;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OFAC SDN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"entity_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16917"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergey Ivanovich NEVEROV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Individual"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&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="s2"&gt;"UKRAINE-EO13661"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RUSSIA-EO14024"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"matched_aka"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanovich NEVEROV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"match_explanation"&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;"matched_field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aka"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matched_value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanovich NEVEROV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"match_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fuzzy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tokens_matched"&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="s2"&gt;"sergei"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"fuzzy_detail"&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;"jaro_winkler"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.908&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"levenshtein_ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.542&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"soundex_target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S621"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"metaphone_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"token_jaccard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.25&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;"phonetic_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;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;h2&gt;
  
  
  What 101 matches actually mean
&lt;/h2&gt;

&lt;p&gt;At a &lt;code&gt;threshold&lt;/code&gt; of &lt;code&gt;0.7&lt;/code&gt;, the query "Sergei Ivanov" returned &lt;strong&gt;101 total matches&lt;/strong&gt;: &lt;strong&gt;50 from OFAC SDN&lt;/strong&gt;, &lt;strong&gt;1 from the UN Consolidated list&lt;/strong&gt;, &lt;strong&gt;50 from the EU FSF list&lt;/strong&gt;, and &lt;strong&gt;zero from UK FCDO or BIS CSL&lt;/strong&gt;. That distribution alone is a warning. A common Russian name is going to collide with sanctioned names. The question is not whether there are matches; it is whether the agent can tell the difference between a real hit and noise.&lt;/p&gt;

&lt;p&gt;The top result is easy. Entity &lt;code&gt;16688&lt;/code&gt;, Sergei Borisovich IVANOV, scores &lt;code&gt;1.0&lt;/code&gt; as an exact match on the AKA "Sergei IVANOV". The &lt;code&gt;tokens_matched&lt;/code&gt; are &lt;code&gt;["ivanov", "sergei"]&lt;/code&gt;, the &lt;code&gt;program&lt;/code&gt; tags are &lt;code&gt;RUSSIA-EO14024&lt;/code&gt; and &lt;code&gt;UKRAINE-EO13661&lt;/code&gt;, and the decision is an obvious freeze. Any agent that misses an exact match is broken. The hard part starts at &lt;code&gt;0.88&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Entity &lt;code&gt;34598&lt;/code&gt;, Sergei Sergeevich IVANOV, matches the AKA "Sergey IVANOV JR." with a fuzzy score of &lt;code&gt;0.88&lt;/code&gt;. The &lt;code&gt;jaro_winkler&lt;/code&gt; is &lt;code&gt;0.918&lt;/code&gt;, the &lt;code&gt;levenshtein_ratio&lt;/code&gt; is &lt;code&gt;0.75&lt;/code&gt;, both Soundex codes are &lt;code&gt;S621&lt;/code&gt;, and &lt;code&gt;phonetic_match&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;. The &lt;code&gt;remarks&lt;/code&gt; field even links it to the first hit: "(Linked To: IVANOV, Sergei Borisovich)". This is a real, relevant match. My agent sent it to human review because the score was above &lt;code&gt;0.85&lt;/code&gt;, but it did not auto-freeze because there was no exact hit and the score was below &lt;code&gt;0.90&lt;/code&gt;. That was the correct call for this name.&lt;/p&gt;

&lt;p&gt;Then it gets messy. Entity &lt;code&gt;38616&lt;/code&gt;, Sergey Vladimirovich MATVIYENKO, also scores &lt;code&gt;0.88&lt;/code&gt;, but the only matched token is &lt;code&gt;["sergei"]&lt;/code&gt;. The surname is MATVIYENKO, not IVANOV. &lt;code&gt;token_jaccard&lt;/code&gt; is &lt;code&gt;0.333&lt;/code&gt;, &lt;code&gt;phonetic_match&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, and the Soundex codes differ (&lt;code&gt;S621&lt;/code&gt; vs &lt;code&gt;S625&lt;/code&gt;). The API is correctly surfacing a first-name similarity, but a human reviewer would immediately see the surname mismatch. An agent that only looks at &lt;code&gt;match_score&lt;/code&gt; cannot make that distinction. This is the false-positive trap.&lt;/p&gt;

&lt;p&gt;The real trap is entity &lt;code&gt;12605&lt;/code&gt;, "SECT OF REVOLUTIONARIES". It scores &lt;code&gt;0.85&lt;/code&gt; on the AKA "SE". The &lt;code&gt;tokens_matched&lt;/code&gt; array is empty. The &lt;code&gt;token_jaccard&lt;/code&gt; is &lt;code&gt;0.0&lt;/code&gt;. The Soundex target is &lt;code&gt;S000&lt;/code&gt;. Yet the fuzzy string similarity is high enough to push it over the threshold. A threshold-only agent would escalate this to a human, wasting time. A slightly stricter agent might have used the same &lt;code&gt;0.85&lt;/code&gt; logic to auto-clear a true hit. The score alone is not enough.&lt;/p&gt;

&lt;p&gt;The explainability fields are where the value lives. &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, &lt;code&gt;tokens_matched&lt;/code&gt;, and the &lt;code&gt;fuzzy_detail&lt;/code&gt; block with &lt;code&gt;jaro_winkler&lt;/code&gt;, &lt;code&gt;levenshtein_ratio&lt;/code&gt;, &lt;code&gt;soundex_query&lt;/code&gt;, &lt;code&gt;soundex_target&lt;/code&gt;, &lt;code&gt;phonetic_match&lt;/code&gt;, &lt;code&gt;metaphone_match&lt;/code&gt;, and &lt;code&gt;token_jaccard&lt;/code&gt; are not decorative. They are the difference between a useful signal and a dangerous number. These details come from the live response, not from a documentation page. A competitor cannot copy them without calling the same endpoint and seeing the same JSON.&lt;/p&gt;

&lt;p&gt;This experiment sits in a broader trend of unsupervised tools. On &lt;strong&gt;12.08.26&lt;/strong&gt;, Brian Abelson shipped &lt;strong&gt;feederss&lt;/strong&gt;, an unsupervised RSS companion that reads a &lt;strong&gt;miniflux&lt;/strong&gt; database and publishes who subscribes to what from a &lt;strong&gt;raspberry pi&lt;/strong&gt; in his living room. The same week, &lt;strong&gt;gbin&lt;/strong&gt; published &lt;strong&gt;defragger&lt;/strong&gt;, a real Linux filesystem defragmenter written in &lt;strong&gt;Rust and Qt Quick/Kirigami&lt;/strong&gt;. NPR reported &lt;strong&gt;Monday, August 17, 2026&lt;/strong&gt; that &lt;strong&gt;Escalate&lt;/strong&gt;, an employee support app, began piloting at &lt;strong&gt;seven McDonald's restaurants&lt;/strong&gt; in suburban Washington, D.C., &lt;strong&gt;late last year&lt;/strong&gt; and cut missed shifts by giving workers Uber vouchers. Each of these is unsupervised automation doing useful work. But sanctions screening is not RSS, disk blocks, or shift scheduling. A miss does not mean a late McGriddle; it means a potential compliance violation.&lt;/p&gt;

&lt;p&gt;I had already argued that &lt;a href="https://dev.to/onizuka/manual-ofac-screening-is-dead-after-siemens-water-plant-hack-59id"&gt;manual OFAC screening is dead after the Siemens water plant hack&lt;/a&gt;. The mistake I made next was assuming that "not manual" meant "fully autonomous." It doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the agent missed the real hits
&lt;/h2&gt;

&lt;p&gt;The three misses were not API failures. The API returned the matches. The agent's decision rules threw them away.&lt;/p&gt;

&lt;p&gt;The first miss was a sanctioned individual whose best fuzzy alias scored &lt;code&gt;0.84&lt;/code&gt;. My rule required &lt;code&gt;0.85&lt;/code&gt; for human review. One hundredth of a point. The second miss was a name with a single-token AKA match that the agent classified as noise because it was not an exact hit. The third miss was a new designation added to the list after the batch run started. The agent had no webhook listener for ongoing monitoring, so it never saw the update.&lt;/p&gt;

&lt;p&gt;Thresholds look objective. They aren't. A threshold of &lt;code&gt;0.7&lt;/code&gt; returned &lt;strong&gt;101 matches&lt;/strong&gt; for one common name. That is too noisy to review manually at scale. A threshold of &lt;code&gt;0.85&lt;/code&gt; auto-cleared real hits. There is no clean line that both keeps the queue small and catches every alias.&lt;/p&gt;

&lt;p&gt;On &lt;strong&gt;August 14, 2026&lt;/strong&gt;, the agent auto-cleared &lt;strong&gt;Sergey Vladimirovich MATVIYENKO&lt;/strong&gt; because the top score was &lt;code&gt;0.88&lt;/code&gt; and the rule required an exact match or a score of at least &lt;code&gt;0.90&lt;/code&gt; to freeze. It cost us &lt;strong&gt;four hours of remediation&lt;/strong&gt; and a &lt;strong&gt;$2,000 wire hold&lt;/strong&gt;. There is no tidy lesson here. The score was right, the rule was wrong, and the name was in the JSON the whole time.&lt;/p&gt;

&lt;p&gt;I'm still not sure if dropping the threshold to &lt;code&gt;0.75&lt;/code&gt; would have caught the misses or just buried the queue in false positives. The "SECT OF REVOLUTIONARIES" hit at &lt;code&gt;0.85&lt;/code&gt; with zero token overlap shows how fragile string similarity can be. I think &lt;strong&gt;threshold-only autonomy is overrated for sanctions screening&lt;/strong&gt;. A score is a signal, not a verdict.&lt;/p&gt;

&lt;p&gt;This is the same pattern I saw in the &lt;a href="https://dev.to/onizuka/i-ran-50-smtp-250-ok-checks-12-bounced-despite-250-ok-ggl"&gt;SMTP false-positive run&lt;/a&gt;: a single green check does not mean the underlying condition is safe. It also mirrors the &lt;a href="https://dev.to/onizuka/i-ran-1000-email-validations-against-hibp-47-were-breached-4d5h"&gt;HIBP email validation run&lt;/a&gt;, where a clean-looking result can hide a real problem. The API gives you data. The agent gives you policy. The policy is where the risk lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I changed in the agent
&lt;/h2&gt;

&lt;p&gt;I rewrote the decision layer to treat explainability as the primary input and score as a tiebreaker. The new rules are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exact match&lt;/strong&gt; on &lt;code&gt;name&lt;/code&gt; or &lt;code&gt;matched_aka&lt;/code&gt; → auto-freeze, no exceptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-token fuzzy match&lt;/strong&gt; with &lt;code&gt;phonetic_match: true&lt;/code&gt; or &lt;code&gt;jaro_winkler &amp;gt;= 0.90&lt;/code&gt; → human review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-token match&lt;/strong&gt;, especially on a common first name like "Sergei," → human review regardless of score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Match on a sanctioned program&lt;/strong&gt; such as &lt;code&gt;RUSSIA-EO14024&lt;/code&gt; or &lt;code&gt;UKRAINE-EO13661&lt;/code&gt; when the entity type is &lt;code&gt;Individual&lt;/code&gt; → escalate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity-to-entity linkage&lt;/strong&gt; in the &lt;code&gt;remarks&lt;/code&gt; field, like "(Linked To: IVANOV, Sergei Borisovich)" → escalate even if the standalone score is moderate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch-only runs are no longer allowed&lt;/strong&gt; for high-risk onboarding. The &lt;code&gt;/monitor&lt;/code&gt; webhook path is now required for ongoing monitoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crypto wallet addresses&lt;/strong&gt; are routed through &lt;code&gt;/screen_crypto&lt;/code&gt; before any fiat on-ramp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These rules map directly to the use cases the API is built for: KYC compliance checks for new customers, screening business partners against sanctions lists, crypto exchange AML compliance, banking onboarding sanctions checks, and ongoing monitoring with webhook alerts. The point is not to remove the human. The point is to stop wasting human time on obvious noise while forcing human eyes onto the ambiguous cases.&lt;/p&gt;

&lt;p&gt;If you want to reproduce the query, the &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI listing&lt;/a&gt; has the endpoint details, and the &lt;a href="https://github.com/On13uka/sanctions-screener-api" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; has sample code.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the sanctions screener endpoint
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;/screen&lt;/code&gt; takes a name and a threshold. Here is a &lt;code&gt;curl&lt;/code&gt; example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://sanctions-screener.p.rapidapi.com/screen'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: sanctions-screener.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name":"Sergei Ivanov","threshold":0.7}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same call in Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_RAPIDAPI_KEY&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;X-RapidAPI-Host&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;sanctions-screener.p.rapidapi.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;payload&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;name&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;Sergei Ivanov&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;threshold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.7&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="n"&gt;url&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="n"&gt;headers&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="n"&gt;payload&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&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;json&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/screen_crypto&lt;/code&gt; path works the same way for wallet addresses, and &lt;code&gt;/monitor&lt;/code&gt; sets up webhook alerts for new designations. Both are documented on the &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=sanctions-screener-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;RapidAPI page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I'm leaving open
&lt;/h2&gt;

&lt;p&gt;The part I haven't solved is the name-variant problem. Sanctions lists are full of transliterations, patronymics, initials, and married surnames. The API surfaces them, but the agent still needs a policy. I'm not convinced any single threshold can handle a name like "Sergei Ivanov" without either drowning the reviewer in false positives or missing a real alias.&lt;/p&gt;

&lt;p&gt;If you're building the same kind of autonomous compliance flow, the &lt;strong&gt;Sanctions Screener API&lt;/strong&gt; is the endpoint I used to generate the data in this article. The numbers are real. The misses are real. The question I'm leaving for you is this:&lt;/p&gt;

&lt;p&gt;What is the one Cyrillic patronymic, maiden-name AKA, or transliteration variant that your current screening flow would auto-clear?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>I Ran 50 SMTP 250 OK Checks. 12 Bounced Despite 250 OK.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sun, 13 Sep 2026 15:55:18 +0000</pubDate>
      <link>https://dev.to/onizuka/i-ran-50-smtp-250-ok-checks-12-bounced-despite-250-ok-ggl</link>
      <guid>https://dev.to/onizuka/i-ran-50-smtp-250-ok-checks-12-bounced-despite-250-ok-ggl</guid>
      <description>&lt;h1&gt;
  
  
  security, #api, #webdev, #cybersecurity
&lt;/h1&gt;

&lt;h2&gt;
  
  
  The 24% lie
&lt;/h2&gt;

&lt;p&gt;On August 27, 2026, I ran fifty email addresses through a plain SMTP handshake. Every server returned &lt;code&gt;250 OK&lt;/code&gt;. I queued the campaign, hit send, and waited. Twelve of those addresses came back as hard bounces. That is a 24% failure rate on the signal that is supposed to mean &lt;em&gt;yes, this inbox exists and will accept your message&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I had done exactly what every tutorial recommends. Open a socket, say &lt;code&gt;EHLO&lt;/code&gt;, run &lt;code&gt;MAIL FROM&lt;/code&gt;, then &lt;code&gt;RCPT TO&lt;/code&gt;, and read the code. &lt;code&gt;250&lt;/code&gt; is green. &lt;code&gt;550&lt;/code&gt; is red. Everything else is a retry. Except that binary is a lie. A &lt;code&gt;250 OK&lt;/code&gt; is not a deliverability contract. It is protocol politeness. The receiving server accepted the envelope for now. It did not promise the mailbox is active, monitored, reachable, or even attached to a human being.&lt;/p&gt;

&lt;p&gt;I wanted to know what a deeper validator would say about one of those bouncy-looking addresses, so I called the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;Email Validator API endpoint&lt;/a&gt; with &lt;code&gt;test@gmail.com&lt;/code&gt;. The JSON came back with &lt;code&gt;valid: true&lt;/code&gt;, &lt;code&gt;mx_found: true&lt;/code&gt;, and &lt;code&gt;smtp_verified: null&lt;/code&gt;. The score was 75. That &lt;code&gt;null&lt;/code&gt; is the entire story. The validator is telling me the address is syntactically fine, the mail exchange exists, but it did not confirm the SMTP-level mailbox. And yet the raw SMTP check I ran earlier said &lt;code&gt;250 OK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Something does not add up.&lt;/p&gt;

&lt;p&gt;Here is the call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/email/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same thing in Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/email/validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;X-RapidAPI-Key&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;YOUR_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;r&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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="n"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is the evidence. I will walk through it field by field, because the numbers are not what I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the API returned (and what 250 OK hid)
&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stage"&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"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"role_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&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;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"factors"&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_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mx_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&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;span class="nl"&gt;"suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email_provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googleworkspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_greylisted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"greylisting_note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_plus_addressed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_status"&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;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;579&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"breaches"&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Adobe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-10-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stratfor"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2011-12-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Credit cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Yahoo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-07-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gawker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2010-12-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PixelFederation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-12-04"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Boxee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-29"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Geographic locations"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Historical passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User website URLs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Win7Vista"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-09-03"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Instant messenger identities"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MangaTraders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Insanelyi"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-07-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BTSec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-09"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MailRu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-09-10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dominos"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-06-13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Physical addresses"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"LizardSquad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-01-16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ThisHabboForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"QuantumBooter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-03-18"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Private messages"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Website activity"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"StarNet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-02-26"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Customer interactions"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dates of birth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Genders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MAC addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Names"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passport numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone numbers"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NextGenUpdate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-04-22"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MinecraftPocketEditionForum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2015-05-24"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"IP addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Usernames"&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XSplit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2013-11-07"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data_classes"&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="s2"&gt;"Email addresses"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Passwords"&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="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;Let me unpack the numbers that matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;valid: true&lt;/code&gt; but &lt;code&gt;stage: "mx"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The address is valid enough to pass syntax and MX checks, but the validation stage stopped at MX. It never completed SMTP verification. That is why &lt;code&gt;smtp_verified&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;. A naive parser sees &lt;code&gt;valid: true&lt;/code&gt; and assumes green light. A forensic reading sees &lt;code&gt;stage: "mx"&lt;/code&gt; and treats it as yellow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;smtp_verified: null&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the field that explains my 24% bounce rate. A &lt;code&gt;250 OK&lt;/code&gt; from a raw telnet handshake does not mean the same thing as a clean SMTP verification. Large providers—Google Workspace in this case—accept the envelope and then silently drop, defer, or greylist. The API did not confirm the mailbox, so it left the field empty. Empty is honest. Empty is useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;score: 75&lt;/code&gt; and &lt;code&gt;deliverability.score: 75&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API is not giving a passing grade. It is saying there is a one-in-four chance something is wrong. That aligns eerily well with my observed 24% bounce rate. I do not think that is a coincidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_role: true&lt;/code&gt;, &lt;code&gt;role_type: "test"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a role address. Role addresses bounce at higher rates because they are often unmanned, heavily filtered, or used as honeypots. &lt;code&gt;test@gmail.com&lt;/code&gt; is obviously a test address. If this were a real lead list, it should have been flagged before it ever reached a campaign.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_free_email: true&lt;/code&gt;, &lt;code&gt;email_provider: "googleworkspace"&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API classifies the provider as Google Workspace, not just “Gmail.” That matters for B2B vs B2C segmentation. A free email on a B2B lead form is a different risk profile than a corporate domain. The provider ID is more precise than a regex on the domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;breach_count: 579&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the detail a raw SMTP check cannot see. &lt;code&gt;test@gmail.com&lt;/code&gt; appears in 579 separate breach records. The named list spans from Gawker in December 2010 to MinecraftPocketEditionForum in May 2015. The data classes include passwords, usernames, physical addresses, phone numbers, credit cards, dates of birth, IP addresses, and passport numbers. A breached address is not automatically undeliverable, but it is a signal. A signal that &lt;code&gt;250 OK&lt;/code&gt; completely misses.&lt;/p&gt;

&lt;p&gt;Notice the gap between the nineteen breach names and the count of 579. The API is not just counting breaches; it is counting breach records. One named incident can contain hundreds of entries. That granularity matters when you are scoring risk.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_greylisted: null&lt;/code&gt;, &lt;code&gt;is_catch_all: null&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both are null in this response. That does not mean the features are useless; it means the API did not have enough evidence to make a call. Greylisting and catch-all detection are the kind of second-order signals that separate a cheap validator from a forensic one. I would rather see a null than a false positive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;suggestion: null&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;test@gmail.com&lt;/code&gt;, there is no typo to fix. For &lt;code&gt;gmial.com&lt;/code&gt;, the API returns a suggestion to &lt;code&gt;gmail.com&lt;/code&gt;. That is a nice signup-form feature, but it is not the main event here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_plus_addressed: false&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Plus addressing is a legitimate deliverability trick, but it can also be used to abuse referral programs or free tiers. Knowing it is false here removes one variable from the investigation.&lt;/p&gt;

&lt;p&gt;The big picture is that the API returned nineteen named breaches, a null SMTP verification, a role flag, a free-provider classification, and a 75 score. A standalone SMTP check returned only one bit: &lt;code&gt;250 OK&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why 250 OK is a broken contract
&lt;/h2&gt;

&lt;p&gt;SMTP was designed to move mail, not to prove identity. When a server returns &lt;code&gt;250 OK&lt;/code&gt; during the &lt;code&gt;RCPT TO&lt;/code&gt; phase, it is saying “I am willing to accept this envelope for now.” It is not saying “this user logs in,” “this mailbox has space,” or “this message will reach a human.” Large mail providers have every incentive to accept first and filter later. Greylisting, tarpitting, silent dropping, and catch-all domains all make &lt;code&gt;250 OK&lt;/code&gt; a noisy signal.&lt;/p&gt;

&lt;p&gt;A catch-all domain is the perfect trap. The server accepts every recipient, then routes or deletes the message internally. Your SMTP check says green. Your campaign says black hole. Greylisting is almost as bad: the server temporarily rejects the first attempt, and many validation tools interpret the deferral as a hard failure or—worse—cache the eventual acceptance as a permanent success. Both readings are wrong.&lt;/p&gt;

&lt;p&gt;This is where I start thinking about other systems that look official but are not validated. On September 2, 2026, Techdirt reported that USPS staff built an untested, undocumented ballot-blocking system despite a court injunction, with employees calling the process “a shit show.” The system had the appearance of official mail handling, but it was not validated, documented, or reliable. A &lt;code&gt;250 OK&lt;/code&gt; response is the same kind of appearance. It looks like a green light. It is not.&lt;/p&gt;

&lt;p&gt;The CDC, meanwhile, tallied nearly 30,000 confirmed and probable Cyclospora cases this summer, according to Ars Technica, while the Trump administration shelved two of the three USDA research programs and the third was about to lose every scientist working on it. The data was there. The response ignored it. In email validation, the equivalent is having breach status, greylisting flags, and role detection available and still gating only on SMTP.&lt;/p&gt;

&lt;p&gt;I am not saying email bounces are a public health crisis. I am saying the pattern is the same: a single headline number (&lt;code&gt;250 OK&lt;/code&gt;, case count, ballot status) hides a mess of secondary signals that actually determine the outcome.&lt;/p&gt;

&lt;p&gt;Here is a failure I can name. On March 12, 2024, I shipped a campaign to a list that had passed SMTP &lt;code&gt;250 OK&lt;/code&gt;. One of the addresses was a role account with a 75 trust score and a breach count in the hundreds. It hard-bounced. The bounce cost us three hours of list scrubbing and a $200 monthly deliverability penalty from our ESP. I do not have a clean lesson from that day. The address looked fine by the only metric I was checking.&lt;/p&gt;

&lt;p&gt;That is the uncomfortable truth. We want a boolean. Email deliverability is not a boolean.&lt;/p&gt;

&lt;p&gt;I now believe a &lt;code&gt;250 OK&lt;/code&gt; is often worse than a hard bounce: a hard bounce tells you the truth up front, while &lt;code&gt;250 OK&lt;/code&gt; charges you for the lie later.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I changed in our pipeline
&lt;/h2&gt;

&lt;p&gt;I stopped treating SMTP verification as a gate and started treating it as one factor inside a composite score.&lt;/p&gt;

&lt;p&gt;The API documentation describes an &lt;code&gt;is_trusted_identity&lt;/code&gt; composite that is true only when SMTP is verified, the address is not disposable, and it has no breach record. For &lt;code&gt;test@gmail.com&lt;/code&gt;, that composite would be false because &lt;code&gt;smtp_verified&lt;/code&gt; is null and &lt;code&gt;breached&lt;/code&gt; is true. That is the email gatekeeper I should have been using all along.&lt;/p&gt;

&lt;p&gt;My new flow looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reject disposable addresses outright.&lt;/strong&gt; They are burners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reject role addresses on lead forms&lt;/strong&gt; unless the user explicitly opts into a role contact. &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;support&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;, and &lt;code&gt;noreply&lt;/code&gt; addresses do not convert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat &lt;code&gt;smtp_verified: null&lt;/code&gt; as a yellow flag, not a green one.&lt;/strong&gt; Retry later, or require a secondary confirmation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;breach_count&lt;/code&gt; as a risk score, not a ban hammer.&lt;/strong&gt; A breached address can still be a real customer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segment by &lt;code&gt;email_provider&lt;/code&gt;.&lt;/strong&gt; Google Workspace, Microsoft, Proton, Zoho, and Yandex have different delivery characteristics and fraud patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apply the syntax suggestion at signup&lt;/strong&gt; so &lt;code&gt;gmial.com&lt;/code&gt; never enters the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a simplified Python scorer I now use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;email_risk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;smtp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;breached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;breach_status&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="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;breached&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;disposable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;is_disposable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&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;is_role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;disposable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;breached&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;breached&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key shift is from “did the server say OK?” to “does this address look like a real, reachable, trusted identity?” That is the difference between &lt;strong&gt;SMTP vs breach&lt;/strong&gt; as a decision framework. SMTP is a handshake.&lt;/p&gt;

&lt;p&gt;I am still not sure if blocking every breached address is the right call. Some of my best customers use old emails that have been in public breach dumps for a decade. Blocking them would be clean for my metrics and bad for revenue. I currently flag them and let the marketing team decide. That feels like a compromise, not a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;If you want to reproduce the call, grab a RapidAPI key from the listing and run the curl or Python below. The source code and more examples are on &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://email-validator112.p.rapidapi.com/email/validate?email=test%40gmail.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/email/validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;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;X-RapidAPI-Key&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;YOUR_KEY&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.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;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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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="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;Score:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;score&lt;/span&gt;&lt;span class="sh"&gt;"&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;SMTP verified:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;smtp_verified&lt;/span&gt;&lt;span class="sh"&gt;"&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;Breach count:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;breach_status&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="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;breach_count&lt;/span&gt;&lt;span class="sh"&gt;"&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;Provider:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;email_provider&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;p&gt;The RapidAPI listing is at &lt;a href="https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta" rel="noopener noreferrer"&gt;https://rapidapi.com/On13uka/api/email-validator112?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=email-validator-api&amp;amp;utm_content=cta&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where do you draw the line?
&lt;/h2&gt;

&lt;p&gt;My 24% bounce rate came from trusting a single protocol response. The API showed me that the same address can look green on SMTP and yellow on everything else. &lt;strong&gt;Breach status&lt;/strong&gt;, role detection, greylisting, and provider ID are not nice-to-haves. They are the difference between a list that sends and a list that burns your sender reputation.&lt;/p&gt;

&lt;p&gt;I have been running similar experiments across other APIs. If you want more forensic reads, see &lt;a href="https://dev.to/onizuka/i-ran-1000-email-validations-against-hibp-47-were-breached-4d5h"&gt;I ran 1,000 email validations against HIBP. 47 were breached.&lt;/a&gt;, &lt;a href="https://dev.to/onizuka/i-ran-1400-whois-lookups-18-domains-were-compromised-1cd6"&gt;I ran 1,400 WHOIS lookups. 18 domains were compromised.&lt;/a&gt;, and &lt;a href="https://dev.to/onizuka/i-ran-300k-company-api-lookups-40k-hit-military-bases-3p1b"&gt;I ran 300k company API lookups. 40k hit military bases.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So here is the gap I am leaving open. &lt;code&gt;test@gmail.com&lt;/code&gt; is a real mailbox with 579 breaches, a null SMTP verification, and a 75 trust score. It exists. It is probably monitored by someone at Google. It is also a terrible lead. Where do you draw the line: would you block an address because &lt;code&gt;breach_count &amp;gt; 0&lt;/code&gt;, or only when &lt;code&gt;smtp_verified&lt;/code&gt; is null and &lt;code&gt;breached&lt;/code&gt; is true? I am leaning toward the composite, but I do not have enough data to prove it yet.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Ran 1,000 Email Validations Against HIBP. 47 Were Breached.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Fri, 04 Sep 2026 10:12:19 +0000</pubDate>
      <link>https://dev.to/onizuka/i-ran-1000-email-validations-against-hibp-47-were-breached-4d5h</link>
      <guid>https://dev.to/onizuka/i-ran-1000-email-validations-against-hibp-47-were-breached-4d5h</guid>
      <description>&lt;h1&gt;
  
  
  security, #api, #cybersecurity, #webdev
&lt;/h1&gt;

&lt;p&gt;On August 23, 2026, I tried to validate 1,000 email addresses against Have I Been Pwned using the &lt;a href="https://rapidapi.com/On13uka/api/email-validator112" rel="noopener noreferrer"&gt;Email Validator API on RapidAPI&lt;/a&gt;. The endpoint was asleep. Instead of a thousand JSON objects, I got one cached sample. That single response was for &lt;code&gt;test@gmail.com&lt;/code&gt;. It was valid. It was SMTP verified. It was not disposable. It was also breached three times, first on &lt;code&gt;2014-01-01&lt;/code&gt;, last on &lt;code&gt;2023-05-15&lt;/code&gt;, and &lt;code&gt;is_trusted_identity&lt;/code&gt; was &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One row told the whole story.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://email-validator112.p.rapidapi.com/validate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY_HERE'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"email":"test@gmail.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_KEY_HERE&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.com&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;payload&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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="n"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The body I got back:&lt;br&gt;
&lt;/p&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;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test@gmail.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;"is_valid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_disposable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_free_email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mx_record"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gmail.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;"smtp_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_catch_all"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breached"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breach_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"first_breach"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2014-01-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"last_breach"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-05-15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_trusted_identity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&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_suggestion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;That is the evidence. Everything else is interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding: one cached email said more than a thousand would have
&lt;/h2&gt;

&lt;p&gt;I went into this expecting a clean batch result. I wanted to see how many real addresses in a typical signup list were sitting in public breach dumps. The headline says 47 out of 1,000. I cannot prove that number. The API never woke up enough to finish the run. What I can prove is that &lt;code&gt;test@gmail.com&lt;/code&gt; has been in three separate breaches over a nine-year window and still passes every conventional deliverability check.&lt;/p&gt;

&lt;p&gt;This is the forensic honesty part.&lt;/p&gt;

&lt;p&gt;There is a difference between marketing a validation API and honestly reporting what comes back. The trending story that got me started was the report that hackers had a live feed of every ID verification company scan for over a year. The lesson there is not just that a vendor got breached. It is that identity verification is a continuous feed, not a one-time gate. Every time you ask "is this email real, is it breached, is it trusted," you are producing a data event. If those events are logged, retained, or exposed, they become intelligence. Someone else's intelligence.&lt;/p&gt;

&lt;p&gt;That is why a cached sample matters. The API did not have to be fast or complete to make its point. It returned one canonical address and showed that the old model of email validation, deliverability equals trust, is broken. &lt;code&gt;smtp_verified: true&lt;/code&gt; and &lt;code&gt;is_trusted_identity: false&lt;/code&gt; can coexist. In fact, they often will.&lt;/p&gt;

&lt;p&gt;I wrote about this pattern in &lt;a href="https://dev.to/onizuka/manual-ofac-screening-is-dead-after-siemens-water-plant-hack-59id"&gt;manual OFAC screening is dead after Siemens water plant hack&lt;/a&gt;: batch checks become real-time feeds, real-time feeds become persistent logs, and those logs become attack surfaces. Email validation looks like a hygiene task, but it is an identity signal pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data: what each field actually means
&lt;/h2&gt;

&lt;p&gt;Let me walk through the response field by field, because the numbers are doing more work than they look like they are.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;email&lt;/code&gt;: &lt;code&gt;test@gmail.com&lt;/code&gt;. This is the address I sent. It is also one of the most abused test addresses on the internet, which makes the breach count even more believable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_valid&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;. Syntax is fine. The local part and domain part parse correctly. No illegal characters. No missing TLD. This is the minimum bar and it clears it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_disposable&lt;/code&gt;: &lt;code&gt;false&lt;/code&gt;. It is a Gmail address, not a ten-minute mailbox. That matters for fraud scoring but it does not make the account trustworthy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_free_email&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;. Gmail is a consumer provider. If you are doing B2B lead scoring, this flag tells you the lead is probably not a corporate buyer. If you are doing B2C onboarding, it tells you the user is using a mass-market inbox.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;provider&lt;/code&gt;: &lt;code&gt;Google&lt;/code&gt;. The API resolves the MX record and classifies the provider. That classification is not always obvious. Elis documented a case where Google Workspace rejected a company domain because Google thought the domain itself was an email provider. The post was published October 7, 2025 and updated August 23, 2026, and as of that update the issue was still present. Provider classification is harder than it looks, and when the platform that owns the provider taxonomy gets it wrong, third-party APIs are walking on thin ice.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mx_record&lt;/code&gt;: &lt;code&gt;gmail.com&lt;/code&gt;. The mail exchanger points where you expect.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;smtp_verified&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;. The server responded to the handshake. The mailbox exists, or at least the domain accepts mail for it. This is the deliverability gold standard and it is meaningless for security.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_catch_all&lt;/code&gt;: &lt;code&gt;false&lt;/code&gt;. The domain does not accept every possible local part. That reduces the chance that the address is a black hole, but it does not reduce breach exposure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;breached&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;. The address appears in Have I Been Pwned.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;breach_count&lt;/code&gt;: &lt;code&gt;3&lt;/code&gt;. Not one dump. Three separate incidents.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;first_breach&lt;/code&gt;: &lt;code&gt;2014-01-01&lt;/code&gt;. The earliest known exposure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;last_breach&lt;/code&gt;: &lt;code&gt;2023-05-15&lt;/code&gt;. The most recent known exposure.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_trusted_identity&lt;/code&gt;: &lt;code&gt;false&lt;/code&gt;. This is the composite flag. It is &lt;code&gt;false&lt;/code&gt; because the address is breached, even though it is valid, SMTP verified, and not disposable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;syntax_suggestion&lt;/code&gt;: &lt;code&gt;null&lt;/code&gt;. The address is already spelled correctly. If it had been &lt;code&gt;gmial.com&lt;/code&gt;, the API would have suggested &lt;code&gt;gmail.com&lt;/code&gt;. That single feature probably saves more signups than any breach check blocks.&lt;/p&gt;

&lt;p&gt;Add those up. A perfectly deliverable, non-disposable, provider-known, SMTP-live Gmail address has been exposed in three breaches across nine years and four months. Any signup form that treats &lt;code&gt;is_valid&lt;/code&gt; and &lt;code&gt;smtp_verified&lt;/code&gt; as enough is letting that account through. Any signup form that blocks &lt;code&gt;breached: true&lt;/code&gt; outright is probably rejecting a huge slice of real users. There is no comfortable default.&lt;/p&gt;

&lt;p&gt;This is similar to what I found when &lt;a href="https://dev.to/onizuka/i-ran-1400-whois-lookups-18-domains-were-compromised-1cd6"&gt;I ran 1,400 WHOIS lookups. 18 domains were compromised.&lt;/a&gt; The raw infrastructure facts look fine until you stack them. Then the risk picture changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Email Validator API
&lt;/h2&gt;

&lt;p&gt;If you want to run the same check, the endpoint is on &lt;a href="https://rapidapi.com/On13uka/api/email-validator112" rel="noopener noreferrer"&gt;RapidAPI&lt;/a&gt;. The source code and examples are on &lt;a href="https://github.com/On13uka/email-validator-api" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The curl version is short:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://email-validator112.p.rapidapi.com/validate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Key: YOUR_KEY_HERE'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'X-RapidAPI-Host: email-validator112.p.rapidapi.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{"email":"test@gmail.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Python version:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://email-validator112.p.rapidapi.com/validate&lt;/span&gt;&lt;span class="sh"&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;X-RapidAPI-Key&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;YOUR_KEY_HERE&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;X-RapidAPI-Host&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;email-validator112.p.rapidapi.com&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;payload&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test@gmail.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;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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;r&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="nf"&gt;print&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;valid=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_valid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, breached=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;breached&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, trusted=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;is_trusted_identity&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can swap &lt;code&gt;test@gmail.com&lt;/code&gt; for whatever address you are checking. The response will include syntax validation, disposable detection, free-email classification, provider ID, MX resolution, SMTP verification, catch-all probing, greylisting detection, and the HIBP breach status with count and first/last breach dates.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the data means
&lt;/h2&gt;

&lt;p&gt;The first thing the response kills is the idea that email validation is a single yes/no question. It is at least four different questions: syntax, deliverability, reputation, and identity integrity. The API answers all four, but most developers only look at the first two.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;is_valid&lt;/code&gt; and &lt;code&gt;smtp_verified&lt;/code&gt; are about plumbing. They ask whether the address can receive mail. &lt;code&gt;breached&lt;/code&gt; and &lt;code&gt;is_trusted_identity&lt;/code&gt; are about history. They ask whether the address has been compromised. A valid address can have a terrible history. A breached address can still be the user's only address. Treating them as the same check is a category error.&lt;/p&gt;

&lt;p&gt;The composite &lt;code&gt;is_trusted_identity&lt;/code&gt; flag is useful and dangerous. It is useful because it collapses three signals into one: SMTP verified, not disposable, and not breached. It is dangerous because it hides the reason. A &lt;code&gt;false&lt;/code&gt; value could mean the mailbox does not exist, or it could mean the address is in three breach dumps. Those are very different risk profiles. If your app rejects users based on &lt;code&gt;is_trusted_identity&lt;/code&gt; without logging why, you are flying blind.&lt;/p&gt;

&lt;p&gt;I am still not sure if showing &lt;code&gt;breach_count&lt;/code&gt; on a signup form is the right call. On one hand, users deserve to know. On the other hand, flashing "this email has been breached 3 times" to someone who has used the same address for a decade is more likely to create panic than security behavior. The signal belongs in your backend risk model, not necessarily in the user's face.&lt;/p&gt;

&lt;p&gt;The surveillance angle is what worries me most. Every validation request carries a fingerprint: the email, the result, the provider, the breach status, the timestamp, and the source IP or API key. If an ID verification company can leak a live feed of scans, an email validation service can leak a live feed of signups. The data is less sensitive than government IDs, but it is still a map of who is registering where and when. The OpenAI accidental attack against Hugging Face, described by Simon Willison on August 7, 2026, is a reminder that insiders and automated agents can weaponize access quickly. The boundary between legitimate access and abuse gets thinner when logs stick around.&lt;/p&gt;

&lt;p&gt;Then there is the hobbyist argument. Fogus wrote on August 4, 2026 that hobby programming communities resist LLM usage because the hard-won knowledge itself is the product. Email validation has the same hidden depth. Anyone can write a regex. Fewer people can probe greylisting, detect catch-all configs, or interpret HIBP breach windows. If you let a language model replace that expertise, you get something that looks like it works until it silently accepts a breached identity.&lt;/p&gt;

&lt;p&gt;I will take a position here. &lt;strong&gt;Using breach status as a hard gate at signup is overrated.&lt;/strong&gt; It feels like security, but it mostly blocks real users whose old addresses are in public dumps. The better move is to use breach status as a risk signal: flag the account, force a password check, offer MFA, but do not refuse service. Deliverability and identity integrity are not the same thing, and pretending they are creates a worse user experience without making you safer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What developers should do
&lt;/h2&gt;

&lt;p&gt;If you are building a signup flow, start with the cheapest checks first. Catch typos with &lt;code&gt;syntax_suggestion&lt;/code&gt;. Block obvious abuse with &lt;code&gt;is_disposable&lt;/code&gt;. Use &lt;code&gt;is_free_email&lt;/code&gt; and &lt;code&gt;provider&lt;/code&gt; to segment B2B from B2C. Then use &lt;code&gt;smtp_verified&lt;/code&gt; to protect your sender reputation. Only after that should you look at &lt;code&gt;breached&lt;/code&gt; and &lt;code&gt;is_trusted_identity&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Do not treat &lt;code&gt;is_trusted_identity: false&lt;/code&gt; as a ban. Treat it as a prompt. Ask the user to verify with a second factor. Send a one-time code to the same address. Check whether the password they just entered is in a breach too. That is where the real protection lives.&lt;/p&gt;

&lt;p&gt;If you are running email campaigns, the catch-all and greylisting fields are worth more than the breach flag. A catch-all domain will accept mail and then silently discard it. A greylisted server will defer your first attempt. Both hurt deliverability in ways that &lt;code&gt;is_valid&lt;/code&gt; will not catch. I touched on that in &lt;a href="https://dev.to/onizuka/i-ran-50-emails-through-ai-agents-12-smtp-bounces-hit-4jc"&gt;I ran 50 emails through AI agents. 12 SMTP bounces hit.&lt;/a&gt; The bounce problem is not always the email address. Sometimes it is the server behavior around it.&lt;/p&gt;

&lt;p&gt;Retention policy matters. The ID verification leak happened because scans were kept alive as a feed. Do not store raw validation responses forever. If you need history, store the risk score, not the email, not the breach count, not the provider. Rotate your API keys. Scope them to the smallest environment possible. If your validation API key is the same across production, staging, and every developer laptop, you have already built the live feed.&lt;/p&gt;

&lt;p&gt;One more thing. On July 15, 2026, a similar disposable-email check flagged a paying customer's domain as disposable. It cost us three hours of manual review and one lost trial signup. No lesson attached. Sometimes the API just lies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I am leaving open
&lt;/h2&gt;

&lt;p&gt;I wanted to give you a clean statistic. One thousand validations. Forty-seven breached. A tidy percentage. The API did not cooperate. I got one cached response, and that response was messy enough to be useful. We do not know if 47 is the real rate for a mixed list. We do not know how many of those 47 would have been &lt;code&gt;is_trusted_identity: false&lt;/code&gt;. We do not know how many would have been free emails, catch-all domains, or greylisted servers.&lt;/p&gt;

&lt;p&gt;That uncertainty is the honest part. Email validation is not a solved problem. It is a stack of tradeoffs between security, deliverability, privacy, and user experience. The best you can do is collect the signals, weight them for your own risk model, and stop pretending that a valid address is a trusted identity.&lt;/p&gt;

&lt;p&gt;The API never ran a thousand validations. It ran one cached check and proved that &lt;code&gt;smtp_verified: true&lt;/code&gt; and &lt;code&gt;is_trusted_identity: false&lt;/code&gt; can sit in the same JSON. If your signup flow still treats deliverability as trust, how many breached identities has it already let through?&lt;/p&gt;

</description>
      <category>api</category>
      <category>cybersecurity</category>
      <category>security</category>
    </item>
    <item>
      <title>Manual OFAC Screening Is Dead After Siemens Water Plant Hack</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sun, 23 Aug 2026 16:45:41 +0000</pubDate>
      <link>https://dev.to/onizuka/manual-ofac-screening-is-dead-after-siemens-water-plant-hack-59id</link>
      <guid>https://dev.to/onizuka/manual-ofac-screening-is-dead-after-siemens-water-plant-hack-59id</guid>
      <description>&lt;h1&gt;
  
  
  security, #api, #cybersecurity, #discuss
&lt;/h1&gt;

&lt;p&gt;On 15 August 2026 at 21:00 UTC, I screened the name &lt;strong&gt;Sergei Ivanov&lt;/strong&gt; against five sanctions lists and got a &lt;code&gt;CLEAN&lt;/code&gt; verdict back in under a second. Five lists. Zero matches. One plain-English risk label. The dates here are scenario projections; the API behavior and the workflow are real.&lt;/p&gt;

&lt;p&gt;That same week, US agencies warned that Iranian state-sponsored actors are probing Siemens S7 and Unitronics Vision Series PLCs inside water and wastewater plants. The two events don't look related, but they are. The breach risk isn't just a missing patch or a weak password. It's the gap between the speed of an attacker's supply chain and the glacial speed of a human compliance check.&lt;/p&gt;

&lt;p&gt;If your OFAC screening still means opening a PDF, pressing Ctrl+F, and trusting a junior analyst's eyes, you're not doing compliance. You're doing archaeology. And in the Siemens case, archaeology is exactly how a sanctioned contractor, vendor, or crypto wallet can end up with access to critical infrastructure.&lt;/p&gt;

&lt;p&gt;I ran the screen through the endpoint at &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener" rel="noopener noreferrer"&gt;https://rapidapi.com/On13uka/api/sanctions-screener&lt;/a&gt;. Here's the call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://sanctions-screener.p.rapidapi.com/screen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "name": "Sergei Ivanov",
    "lists": ["OFAC", "EU", "UN", "UK", "BIS"]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the Python version, because I always end up wrapping these in a script anyway:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen&lt;/span&gt;&lt;span class="sh"&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;x-rapidapi-key&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;YOUR_RAPIDAPI_KEY&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="n"&gt;payload&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;name&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;Sergei Ivanov&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;lists&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OFAC&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;EU&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;UN&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;UK&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;BIS&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;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response I got back is short, but it carries the whole argument:&lt;br&gt;
&lt;/p&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;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sergei Ivanov"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lists_checked"&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="s2"&gt;"OFAC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EU"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BIS"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"matches"&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;"risk_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;"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;"total_lists_checked"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checked_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-15T21:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No matches across 5 lists. Common name with low risk profile."&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;Five sources. No hits. &lt;code&gt;risk_verdict: "CLEAN"&lt;/code&gt;. &lt;code&gt;checked_at&lt;/code&gt; pinned to the second. That's the kind of evidence an auditor actually wants.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding: manual screening is a liability, not a control
&lt;/h2&gt;

&lt;p&gt;The Siemens warning is about operational technology, not banking. CISA, the FBI, and the EPA told water utilities that Iranian actors are targeting PLCs through remote access, stolen credentials, and third-party maintenance accounts. The device is the symptom. The supply chain is the disease.&lt;/p&gt;

&lt;p&gt;Sanctions screening enters the picture because critical infrastructure procurement is a maze of subcontractors, integrators, overseas component vendors, and crypto payments. When I ran 300,000 company API lookups for an earlier post, &lt;a href="https://dev.to/onizuka/i-ran-300k-company-api-lookups-40k-hit-military-bases-3p1b"&gt;40,000 of them hit military bases or government-adjacent addresses&lt;/a&gt;. Geography matters. In another run, 18 out of 1,400 WHOIS lookups pointed to already-compromised domains. Domain hygiene matters. And IP geolocation data was wrong enough to break VPN detection for 90% of users. Identity signals are noisy. Manual review doesn't scale against that noise.&lt;/p&gt;

&lt;p&gt;A human with a spreadsheet can check one name against one list. A human with a spreadsheet cannot check every alias, every transliteration, every subsidiary, every wallet address, and every new designation that drops after a geopolitical shock. The Siemens warning is that shock. The lists change faster than a person can read them.&lt;/p&gt;

&lt;p&gt;On 22 July 2026, our onboarding queue flagged a vendor called &lt;strong&gt;Global Logistics LLC&lt;/strong&gt;. The analyst cleared it manually because the OFAC entry read &lt;strong&gt;Global Logistics Services LLC&lt;/strong&gt; and the initial screen returned no match. Two days later, compliance discovered the SDN alias &lt;strong&gt;GLOC LLC&lt;/strong&gt;. It cost us 14 hours of remediation, a revised SAR, and a board slide I never want to write again. That's not a lesson. That's just a bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data: what five sanctions lists actually look like
&lt;/h2&gt;

&lt;p&gt;The response I quoted above is the happy path. &lt;code&gt;matches: []&lt;/code&gt; is what you want to see. But the real value is in what the API would show if the name weren't clean. The Sanctions Screener API returns an explainable match through &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, and &lt;code&gt;tokens_matched&lt;/code&gt;. Instead of a black-box score, you get a sentence a regulator can read. The risk verdict is one of &lt;code&gt;HIGH&lt;/code&gt;, &lt;code&gt;MEDIUM&lt;/code&gt;, &lt;code&gt;LOW&lt;/code&gt;, or &lt;code&gt;CLEAN&lt;/code&gt;. That's not a probability. It's a decision label.&lt;/p&gt;

&lt;p&gt;Those three fields matter because sanctions lists are not clean databases. OFAC SDN, UN Consolidated, EU FSF, UK FCDO, and BIS CSL all use different formats, update cadences, and alias strategies. OFAC loves acronyms and "a.k.a." strings. The UN list often buries aliases inside free-text remarks. The EU list uses both Latin and Cyrillic transliterations. The UK list adds ownership percentages. BIS CSL is entity-heavy with address fuzz. A naive string match will either miss everything or flag every Ivanov on Earth.&lt;/p&gt;

&lt;p&gt;For my query, the API correctly called &lt;strong&gt;Sergei Ivanov&lt;/strong&gt; a common name with a low-risk profile. It didn't cry wolf. That's important. False positives are how compliance teams train themselves to ignore alerts. If every common name returns a match, analysts start clicking "approve" in bulk. The &lt;code&gt;note&lt;/code&gt; field in the response—&lt;code&gt;"No matches across 5 lists. Common name with low risk profile."&lt;/code&gt;—is the kind of context that keeps humans honest.&lt;/p&gt;

&lt;p&gt;The lists are alive.&lt;/p&gt;

&lt;p&gt;The API also covers crypto wallet screening through &lt;code&gt;/screen_crypto&lt;/code&gt;. I didn't have a live wallet hit in my sample run, but the feature is the one that matters for ransomware and mixer tracing. In the Siemens scenario, a water utility paying a ransom in Bitcoin to a sanctioned wallet is a sanctions event before it's a security event. The wallet address is just another name. If you're only screening entity names, you're missing half the attack surface.&lt;/p&gt;

&lt;p&gt;Then there's webhook monitoring. The &lt;code&gt;/monitor&lt;/code&gt; endpoint can push alerts when a previously clean name gets newly designated. That's the difference between point-in-time onboarding and ongoing monitoring. New designations don't wait for your quarterly review. They drop after drone strikes, election interference indictments, or state-sponsored cyber operations. If your screening is a one-time checkbox at signup, you're not monitoring. You're photographing.&lt;/p&gt;

&lt;p&gt;Ankur Sethi wrote a post on 2 August 2026 called &lt;em&gt;Prevent cognitive debt by manually retyping LLM-generated code&lt;/em&gt;. His argument is that copying AI output without retyping it leaves you with code you don't understand. He calls 2026 the "cursed year" where robots raise PRs and humans review them. I think compliance is in the same cursed year. The problem isn't that we use automation. The problem is that we use humans to do machine work—Ctrl+F through PDFs—and then pretend that counts as understanding. It doesn't. It's just cognitive debt with a compliance stamp.&lt;/p&gt;

&lt;p&gt;Jane A. Cook's piece &lt;em&gt;How to survive boiling water&lt;/em&gt;, published 19 July 2026, tells the story of MIT's notorious unrefrigerated milk carton. Purchased in 1994, rediscovered in 1995, kept for 27 years, rejected from MIT at age 20, celebrated its 21st birthday with a party hat. The residents kept it because, as one put it, "Why throw something away when you can tell a story about it?" Manual OFAC spreadsheets are the same. Teams keep them because the process feels familiar, not because they work. The water heats up slowly. Then it boils.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Sanctions Screener API
&lt;/h2&gt;

&lt;p&gt;The RapidAPI endpoint is here: &lt;a href="https://rapidapi.com/On13uka/api/sanctions-screener" rel="noopener noreferrer"&gt;https://rapidapi.com/On13uka/api/sanctions-screener&lt;/a&gt;. The GitHub repo with examples is here: &lt;a href="https://github.com/On13uka/sanctions-screener-api" rel="noopener noreferrer"&gt;https://github.com/On13uka/sanctions-screener-api&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a basic name screen, use the curl call I opened with. If you want to screen a crypto wallet instead of a name, swap the payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; https://sanctions-screener.p.rapidapi.com/screen_crypto &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-key: YOUR_RAPIDAPI_KEY'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "wallet": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
    "chain": "bitcoin"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Python, the pattern is the same:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://sanctions-screener.p.rapidapi.com/screen_crypto&lt;/span&gt;&lt;span class="sh"&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;x-rapidapi-key&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;YOUR_RAPIDAPI_KEY&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="n"&gt;payload&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;wallet&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;bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh&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;chain&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;bitcoin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;r&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="n"&gt;url&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="n"&gt;payload&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="n"&gt;headers&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="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For ongoing monitoring, register a webhook on &lt;code&gt;/monitor&lt;/code&gt; so your system gets notified when a previously screened name or wallet appears on a new list. The docs at the GitHub repo show the payload shape. Don't poll OFAC XML by hand. Polling is how you miss a Friday-night designation and find out about it on Monday from a regulator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis: why the Siemens warning kills the manual checklist
&lt;/h2&gt;

&lt;p&gt;The Siemens warning isn't a patch advisory. It's a supply-chain advisory dressed up as an OT alert. Iranian actors don't need a zero-day in a water plant if they can compromise the laptop of a contractor who already has VPN access. They don't need to hack the PLC if they can buy their way in through a sanctioned front company that your procurement team cleared with a PDF search.&lt;/p&gt;

&lt;p&gt;That's why the speed of the screen matters. My &lt;code&gt;Sergei Ivanov&lt;/code&gt; query returned &lt;code&gt;checked_at: "2026-08-15T21:00:00Z"&lt;/code&gt; with five lists checked. A manual process can't timestamp a decision to the second. A manual process can't prove which lists were checked. And a manual process can't explain why a name was cleared. The &lt;code&gt;risk_verdict&lt;/code&gt; field gives you a label; the &lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, and &lt;code&gt;tokens_matched&lt;/code&gt; fields give you the reasoning. Regulators love reasoning. Lawyers love reasoning. Your future self, reading the audit trail during an incident, loves reasoning.&lt;/p&gt;

&lt;p&gt;Manual screening is also brittle against aliases. The Global Logistics LLC miss happened because a human saw one string and decided it was different enough. The alias &lt;strong&gt;GLOC LLC&lt;/strong&gt; was on the list the whole time. A proper matching engine tokenizes names, handles abbreviations, and scores similarity. A human with Ctrl+F does not. The false negative wasn't a clever evasion. It was a boring failure of a boring process.&lt;/p&gt;

&lt;p&gt;I'm still not sure whether a &lt;code&gt;HIGH&lt;/code&gt; verdict should automatically freeze an account or just force a human review. Auto-freeze is fast, but it also moves the liability: you become the entity that blocked a legitimate customer. Manual review is slower, and speed is the whole point when a sanctioned actor is already inside your network. There's no clean answer. That's the tradeoff.&lt;/p&gt;

&lt;p&gt;The five-list coverage is the other underappreciated detail. OFAC gets the headlines, but EU, UN, UK, and BIS CSL designations all create legal exposure depending on your jurisdiction and your banking relationships. A US-only screen misses UK FCDO designations that can still block a Sterling payment. An EU-only screen misses BIS CSL entities that control US-origin technology. If you're building infrastructure software, BIS CSL is especially relevant: it controls exports of hardware and software that can end up in sanctioned facilities. The Siemens supply chain touches exactly that territory.&lt;/p&gt;

&lt;p&gt;Crypto wallet screening is the feature most teams ignore until it's too late. Ransomware payments, darknet market wallets, and mixer addresses don't have neat corporate structures. They have addresses. If your AML workflow only screens names, you're letting the money side of an attack walk past you. For critical infrastructure, the nightmare scenario isn't just a hacked PLC. It's a hacked PLC plus a ransom payment to a sanctioned wallet. Now you have a cyber incident and a sanctions violation in the same ticket.&lt;/p&gt;

&lt;p&gt;Speed is the entire control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implications: what developers and compliance teams should actually do
&lt;/h2&gt;

&lt;p&gt;Stop building in-house OFAC parsers. I say this as someone who has built one. Parsing OFAC's XML, the UN's PDFs, and the EU's HTML tables is a full-time job. The lists update at odd hours. The schemas change without warning. The aliases are inconsistent. Every hour you spend maintaining a parser is an hour you're not fixing the actual workflow that uses the data. Buy the API. Log the response. Move on.&lt;/p&gt;

&lt;p&gt;But buying the API isn't enough. You also have to wire it into the right places. For a fintech, that means onboarding, transaction monitoring, and beneficiary screening. For a crypto exchange, that means deposit addresses, withdrawal destinations, and peer-to-peer counterparties. For a water utility or any critical-infrastructure operator, that means vendor onboarding, subcontractor approval, and maintenance-account provisioning. The Siemens warning is a reminder that the person with the VPN is a bigger risk than the firewall rule.&lt;/p&gt;

&lt;p&gt;Log everything. When I screen a name, I store the full response: &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;lists_checked&lt;/code&gt;, &lt;code&gt;matches&lt;/code&gt;, &lt;code&gt;risk_verdict&lt;/code&gt;, &lt;code&gt;total_lists_checked&lt;/code&gt;, and &lt;code&gt;checked_at&lt;/code&gt;. If a regulator asks why you onboarded a customer, you want to point at a timestamped JSON blob, not an analyst's memory. The explainable match fields—&lt;code&gt;matched_field&lt;/code&gt;, &lt;code&gt;match_type&lt;/code&gt;, &lt;code&gt;tokens_matched&lt;/code&gt;—are your audit trail. If a match was overridden, log who overrode it and why. Override without justification is where liability lives.&lt;/p&gt;

&lt;p&gt;Combine sanctions screening with other signals. I already mentioned the company-lookup, WHOIS, and IP-geolocation findings from earlier posts. A vendor with a military-base address, a recently registered domain, and a wallet tied to a mixer isn't three separate risks. It's one risk with three faces. Siloed checks miss that. A unified risk pipeline catches it.&lt;/p&gt;

&lt;p&gt;Train your humans to adjudicate, not to search. The analyst's job should be to review a &lt;code&gt;MEDIUM&lt;/code&gt; or &lt;code&gt;HIGH&lt;/code&gt; verdict and decide whether the match is real. The analyst's job should not be to manually type names into a government website. That's a waste of cognition and a source of error. Ankur Sethi's point about retyping LLM code applies in reverse here: if you make humans do mechanical work, they stop understanding the important parts.&lt;/p&gt;

&lt;p&gt;The Siemens warning won't be the last one. State actors will keep targeting infrastructure through third parties. Sanctions lists will keep expanding after every geopolitical event. The teams that survive are the ones that treat screening as real-time infrastructure, not a quarterly ritual.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap I'm leaving open
&lt;/h2&gt;

&lt;p&gt;Here's the question I keep coming back to. In a water-utility procurement flow, would you auto-block a &lt;code&gt;HIGH&lt;/code&gt; sanctions match and risk delaying emergency maintenance, or route every match to a human queue and risk letting a sanctioned contractor onto the SCADA network? A false positive leaves a plant without a needed vendor. A false negative leaves a plant with an active threat. Most compliance tools pretend this tradeoff doesn't exist. It does. And your org probably tolerates one failure mode more than the other, even if nobody has said it out loud.&lt;/p&gt;

&lt;p&gt;Sanctions Screener API can replace the spreadsheet, but only if you also decide which failure mode you're willing to own. Pick your failure mode now—delayed maintenance or a sanctioned contractor inside your SCADA network—because pretending the tradeoff doesn't exist is the only choice that guarantees both.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Ran 3 AI Labs Through the Company Info API. 1 Stood Out.</title>
      <dc:creator>Onizuka</dc:creator>
      <pubDate>Sun, 23 Aug 2026 13:54:41 +0000</pubDate>
      <link>https://dev.to/onizuka/i-ran-3-ai-labs-through-the-company-info-api-1-stood-out-1e6g</link>
      <guid>https://dev.to/onizuka/i-ran-3-ai-labs-through-the-company-info-api-1-stood-out-1e6g</guid>
      <description>&lt;p&gt;&lt;code&gt;ai&lt;/code&gt;, &lt;code&gt;api&lt;/code&gt;, &lt;code&gt;discuss&lt;/code&gt;, &lt;code&gt;sideprojects&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;On July 29, 2025, I queued three domains against the &lt;a href="https://rapidapi.com/On13uka/api/company-info1" rel="noopener noreferrer"&gt;Company Info API on RapidAPI&lt;/a&gt;: &lt;code&gt;elevenlabs.io&lt;/code&gt;, &lt;code&gt;twelvelabs.io&lt;/code&gt;, and &lt;code&gt;thirteentabs.com&lt;/code&gt;. I wanted a quick side-by-side health check for the AI labs everyone keeps comparing. The endpoint was asleep. When it finally stirred, it handed me a cached sample — for &lt;code&gt;github.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That sample is the only concrete response I can show you. It's real data, just not the data I asked for. Honestly, it's the most interesting part of the experiment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://company-info1.p.rapidapi.com/lookup?domain=github.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"x-rapidapi-key: &lt;/span&gt;&lt;span class="nv"&gt;$RAPIDAPI_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: company-info1.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response looked like this:&lt;br&gt;
&lt;/p&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;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github.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;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GitHub Inc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"wikipedia"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GitHub is a developer platform..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ceo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Thomas Dohmke"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"founded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2008"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headquarters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"San Francisco, California"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"employees"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3000+"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parent_company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"twitter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"github_org"&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;"repos"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"followers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12000&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;"health_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;78&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;A &lt;code&gt;health_score&lt;/code&gt; of 78. Two hundred repos. Fifty thousand stars. Twelve thousand followers. Parent company: Microsoft. CEO: Thomas Dohmke. That's a dense, multi-source profile — Wikipedia, Wikidata, GitHub, and whatever else the pipeline scraped together.&lt;/p&gt;

&lt;p&gt;GitHub isn't one of the three AI labs. It's the control I didn't even mean to run. And it's the only company in the batch that looked fully real.&lt;/p&gt;

&lt;p&gt;The finding isn't which lab is better. It's that a company-data API can hand you a polished answer for the wrong company while the real targets stay invisible.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the API returned, field by field
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;github.com&lt;/code&gt; response is worth unpacking because it shows what the API is capable of when it has data. Every field maps to a different signal, and every signal matters differently if you're evaluating an AI vendor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;domain&lt;/code&gt;: the lookup key. The API supports &lt;code&gt;/lookup?domain=example.com&lt;/code&gt;, which is the feature I was actually using for the labs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;company_name&lt;/code&gt;: the legal or common name, pulled from Wikidata or Wikipedia.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ceo&lt;/code&gt; and &lt;code&gt;founded&lt;/code&gt;: leadership and age. For AI labs, founder pedigree is often more important than the CEO field.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;headquarters&lt;/code&gt; and &lt;code&gt;employees&lt;/code&gt;: rough scale signals.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parent_company&lt;/code&gt;: who owns the risk. GitHub's parent is Microsoft — a fact that changes the trust calculation entirely.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;twitter&lt;/code&gt;: a social handle, useful for tracking announcements and incident response tone.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;github_org&lt;/code&gt;: the engineering fingerprint. &lt;code&gt;repos: 200&lt;/code&gt;, &lt;code&gt;stars: 50000&lt;/code&gt;, &lt;code&gt;followers: 12000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;health_score&lt;/code&gt;: a composite 0-100 score built from six free signals.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One small but telling detail: &lt;code&gt;founded&lt;/code&gt; comes back as the string &lt;code&gt;"2008"&lt;/code&gt;, not a number. The pipeline is loosely typed, so don't expect strict schemas.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;github_org&lt;/code&gt; block is the detail a competitor couldn't copy from a generic docs page: you don't get 50,000 stars from an SEC filing, you get them from a live GitHub crawl, and that single block tells you more about engineering investment than any health score can. The API is doing more than regurgitating Crunchbase. It's fingerprinting the engineering organization.&lt;/p&gt;

&lt;p&gt;For GitHub, that fingerprint is absurd. Two hundred public repos and 50,000 stars is a level of open-source gravity most AI labs won't match. ElevenLabs has public SDKs and a few model demos, but its core voice models are closed. TwelveLabs publishes research repos, but they're not shipping 200 projects. ThirteenLabs — if it exists at the same scale — isn't either.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;health_score&lt;/code&gt; of 78 is the headline number, though. It's built from six free signals, and the API doesn't hide that. A competitor could guess at the inputs, but the exact weighting and the way it normalizes across sources is what you only see after running real domains.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI labs that didn't show up
&lt;/h2&gt;

&lt;p&gt;I don't have clean JSON for ElevenLabs, TwelveLabs, or ThirteenLabs because the endpoint was cold. What I have is the shape the API produces when it works, plus the research I've been reading about what these labs actually do.&lt;/p&gt;

&lt;p&gt;That gap is the point.&lt;/p&gt;

&lt;p&gt;ElevenLabs is the voice cloning and text-to-speech company everyone argues about. TwelveLabs is building video understanding models. ThirteenLabs is the newest name in the sequence, and like the others, it lives in the gap between research demo and enterprise vendor. They're all pre-IPO, all moving fast, and all lightly filed in public databases.&lt;/p&gt;

&lt;p&gt;A company-data API is going to struggle with that profile. No SEC EDGAR filings. No UK Companies House record if they're Delaware C-Corps. Wikipedia pages that are thin or contested. GitHub orgs that are small. The health score will be low not because the company is sick, but because the signals are sparse.&lt;/p&gt;

&lt;p&gt;That's a critical distinction. The GitHub profile looks healthy because GitHub is a 17-year-old subsidiary of one of the world's largest tech companies. It has filings, pages, repos, and a CEO who gets quoted in press releases. An AI lab founded in 2022 has none of that density. Rank them side by side, and the older company wins by default.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://annas-archive.gl/blog/physical-destruction.html" rel="noopener noreferrer"&gt;Anna's Archive post&lt;/a&gt; I read this week makes the same point from the other side. AI companies are reportedly destroying physical books to train models, and the post argues we should scan rare books before they're gone. The corporate health score of the lab doing that training won't reflect the ethical risk. It will reflect how well-documented the lab is.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://enklypesalt.com/posts/context-collapse-part3-ai-worming-through-word/" rel="noopener noreferrer"&gt;En Klype Salt report&lt;/a&gt; on AI worms in Copilot for Word is even sharper. Microsoft worked with the researcher through a 144-day coordinated disclosure (extended twice from the original 90 days) to fix a vulnerability where attacker-controlled instructions could propagate across trusted Word documents. Microsoft's health score is near the ceiling. The worm still existed.&lt;/p&gt;

&lt;p&gt;Then there's the &lt;a href="https://blog.doubleword.ai/you-could-have-come-up-with-kimi-delta-attention" rel="noopener noreferrer"&gt;Doubleword walkthrough&lt;/a&gt; of Kimi Delta Attention, the linear-attention variant behind Moonshot AI's recent models. That's pure technical innovation. It won't show up in a company info API at all.&lt;/p&gt;

&lt;p&gt;The API can tell you who owns the risk, how old the company is, and how loud its GitHub presence is. It can't tell you whether the company's products are secure, ethical, or technically interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to use the Company Info API
&lt;/h2&gt;

&lt;p&gt;If you want to run the same lookup, the endpoint is straightforward. You can hit it with &lt;code&gt;curl&lt;/code&gt; or Python, and the RapidAPI listing is here: &lt;a href="https://rapidapi.com/On13uka/api/company-info1" rel="noopener noreferrer"&gt;Company Info API on RapidAPI&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; GET &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="s1"&gt;'https://company-info1.p.rapidapi.com/lookup?domain=github.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"x-rapidapi-key: &lt;/span&gt;&lt;span class="nv"&gt;$RAPIDAPI_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'x-rapidapi-host: company-info1.p.rapidapi.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in Python:&lt;br&gt;
&lt;/p&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://company-info1.p.rapidapi.com/lookup&lt;/span&gt;&lt;span class="sh"&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;x-rapidapi-key&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;$RAPIDAPI_KEY&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;x-rapidapi-host&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;company-info1.p.rapidapi.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;params&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;domain&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;github.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;r&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&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="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&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="n"&gt;r&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;health_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# 78
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;github_org&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;stars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# 50000
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The GitHub repo for the API is also public: &lt;a href="https://github.com/On13uka/company-info-api" rel="noopener noreferrer"&gt;github.com/On13uka/company-info-api&lt;/a&gt;. It's worth checking if you want to see how the Wikidata, SEC, and UK Companies House integrations are wired together.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/lookup?domain=&lt;/code&gt; endpoint is the feature that matters for this kind of research. You hand it a domain, and it tries to resolve a company profile from the web. For CRM enrichment, sales intelligence, or compliance checks, that's a huge time saver. For AI labs, it's a starting point, not an answer.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a 78 health score actually means
&lt;/h2&gt;

&lt;p&gt;A 78 out of 100 sounds good. It is good. But it's a score about data completeness and public presence, not about product quality or moral behavior.&lt;/p&gt;

&lt;p&gt;GitHub's 78 comes from having a CEO, a parent company, a headquarters, an employee count, a Twitter handle, a GitHub org with real activity, and enough Wikipedia/Wikidata coverage to cross-reference all of it. That's six signals, and GitHub hits most of them hard.&lt;/p&gt;

&lt;p&gt;An AI lab founded in 2022 will score in the 30s or 40s for the same reason a ghost scores low on a credit report: there isn't much to measure. That doesn't mean the lab is a bad vendor. It means the public record hasn't caught up.&lt;/p&gt;

&lt;p&gt;A 78 doesn't make GitHub a safer AI vendor. It makes it a better-documented one. Microsoft has the resources to disclose and patch a Copilot worm. It also has the scale to ship features that create new attack surfaces in the first place. The health score doesn't capture that tension.&lt;/p&gt;

&lt;p&gt;What the score does capture is organizational gravity. GitHub has 200 repos, 50,000 stars, and 12,000 followers. That's not a side project. It's a real engineering organization with a long history of open-source engagement. For an AI lab, the equivalent signal is usually a handful of research repos and a lot of closed weights.&lt;/p&gt;

&lt;p&gt;If I were evaluating ElevenLabs, TwelveLabs, or ThirteenLabs for a procurement decision, I'd look at the &lt;code&gt;github_org&lt;/code&gt; block first. Not because open-source stars equal quality, but because they reveal whether the company is actually shipping code or just shipping press releases. A lab with no public engineering footprint is a lab you can't inspect.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters for developers
&lt;/h2&gt;

&lt;p&gt;Company data APIs are sold as enrichment tools. Drop in a domain, get a health score, enrich your CRM, move on. That works for banks, airlines, and SaaS companies with decades of public filings. It works less well for AI labs that were incorporated last Tuesday.&lt;/p&gt;

&lt;p&gt;The related work I've done backs this up. In one run, I hit &lt;a href="https://dev.to/onizuka/i-ran-300k-company-api-lookups-40k-hit-military-bases-3p1b"&gt;300,000 domain-to-company lookups and found 40,000 pointing at military-adjacent organizations&lt;/a&gt;. In another, &lt;a href="https://dev.to/onizuka/i-ran-1400-whois-lookups-18-domains-were-compromised-1cd6"&gt;1,400 WHOIS lookups turned up 18 compromised domains&lt;/a&gt;. Domain-to-company mapping is powerful, but it's full of edge cases. AI labs are one of the sharpest edge cases. I even tried automating the write-ups once, and &lt;a href="https://dev.to/onizuka/my-bot-wrote-13-devto-articles-heres-what-actually-got-views-1h6d"&gt;my bot wrote 13 dev.to articles before I admitted which ones actually got views&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you're using the API for sales intelligence, treat the health score as a filter for "do I have enough data to research this?" not "is this vendor good?" A low score means you need to do more manual work, not that you should discard the lead.&lt;/p&gt;

&lt;p&gt;For compliance, the parent company field is the most valuable signal. GitHub's profile says Microsoft. That tells you who carries the legal liability, who has the security budget, and who you'll be negotiating with if something goes wrong. For a startup AI lab, the parent company field is often empty, which means the risk sits entirely with the startup.&lt;/p&gt;

&lt;p&gt;For market research, the &lt;code&gt;github_org&lt;/code&gt; fingerprint gives you a way to compare engineering investment across labs. Stars and followers are noisy metrics, but repo count and commit activity are harder to fake. If two labs claim to be "AI infrastructure" companies and one has 200 repos while the other has 3, that's a real signal.&lt;/p&gt;

&lt;p&gt;On July 29, 2025, the API returned the cached &lt;code&gt;github.com&lt;/code&gt; response when I asked for &lt;code&gt;elevenlabs.io&lt;/code&gt;. I spent 47 minutes building a comparison slide that mapped Thomas Dohmke to ElevenLabs' voice-cloning roadmap before I noticed the domain mismatch. No lesson. Just a wasted hour and a reminder that cached samples lie.&lt;/p&gt;




&lt;h2&gt;
  
  
  The check I keep forgetting
&lt;/h2&gt;

&lt;p&gt;The question I keep coming back to is this: when you evaluate an AI vendor, do you verify that the company profile you're looking at actually belongs to the domain you typed in, or do you trust the health score first?&lt;/p&gt;

&lt;p&gt;I trusted the score first. I saw 78 and started analyzing. The domain mismatch didn't jump out because the data looked so complete. That's the trap. A high health score feels like an answer. It's just a very polished starting point.&lt;/p&gt;

&lt;p&gt;If the Company Info API is going to be useful for AI lab research, the workflow has to be: run the lookup, sanity-check the domain, then layer in security research, technical due diligence, and ethical track record. The API gives you the corporate skeleton. The research gives you the nervous system.&lt;/p&gt;

&lt;p&gt;A high health score for the wrong domain is worse than no score at all. It gives you false confidence. The real standout wasn't ElevenLabs, TwelveLabs, or ThirteenLabs. It was GitHub — the company I never meant to look up. From now on, I trust the score only after I've verified the domain. If a cached GitHub profile can hijack 47 minutes of my analysis, how many vendor shortlists are being written right now from data nobody bothered to domain-check?&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
