Skip to main content

Clean an existing user list

New signups are checked one by one with POST /v1/check. Users you already have can be checked in bulk: up to 50 addresses per request with POST /v1/check/batch, or a whole CSV export with one command. Bulk checks are part of Premium.

What it finds​

Column in the resultWhat to do with it
disposable: trueThe account was opened with a throwaway address. Remove its free credits, or ask the user to change to a permanent address.
deliverable: falseThe address can never receive mail. Your emails to it bounce: ask the user to fix it on next login, or deactivate it.
duplicate_ofAnother account uses the same inbox with a different spelling (john+2@gmail.com, j.o.h.n@gmail.com). Review and merge.
email_normalizedThe canonical inbox. Store it in a unique column so the duplicates can't come back.
relay, alias, found, registrationTrust signals, the same as for single checks: see Check an email.

Option 1: one command​

You need Node.js 20 or later and a Premium API key. Export your users to CSV with an email column, then run:

SIGNITIZE_API_KEY=sk_live_... npx signitize clean users.csv
Checking users.csv -> users.cleaned.csv
Checked 1,000 of 18,250 rows.
...
Rows in file: 18,250
Checked now: 18,212
Disposable: 1,904
Undeliverable: 311
Privacy relay: 97
Duplicates: 1,566 (see duplicate_of)
Errors: 38 (see error)
Output: users.cleaned.csv
Quota left: 81,750 this month
  • users.cleaned.csv contains your columns plus email_normalized, disposable, deliverable, relay, provider, alias, found, registration, duplicate_of and error.
  • duplicate_of is the row number (as in a spreadsheet, with the header on row 1) of the first account with the same inbox. It is empty for the first one.
  • --column <name> picks another column, --out <file> another output file.
  • Resumable: if it stops (quota used up, outage, Ctrl+C), run the same command again. Rows already in the output file are skipped and never counted twice.
  • It waits automatically when the API asks it to slow down, and retries addresses whose check could not complete.
  • Everything runs on your machine. Signitize stores no addresses.

Option 2: your own code​

import { Signitize, isBatchError } from 'signitize'

const signitize = new Signitize() // reads SIGNITIZE_API_KEY

const rows = await signitize.checkBatch(['John+1@gmail.com', 'abc@yopmail.com', 'nope'])
for (const row of rows) {
if (isBatchError(row)) console.log(row.input, row.error.type) // 'ValidationError' or 'InternalServerError'
else console.log(row.input, row.email, row.disposable, row.deliverable)
}

Or with curl:

curl https://api.signitize.io/v1/check/batch \
-H "Authorization: Bearer $SIGNITIZE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"emails":["John+1@gmail.com","abc@yopmail.com","nope"]}'

The response has one row per address, in the order you sent them. A row is either the normal check result plus input, or an error for that address only:

{
"results": [
{ "input": "John+1@gmail.com", "email": "john@gmail.com", "disposable": false, "deliverable": true, "relay": false, "provider": "gmail", "registration": null, "alias": ["plus"], "found": 0 },
{ "input": "abc@yopmail.com", "email": "abc@yopmail.com", "disposable": true, "deliverable": true, "relay": false, "provider": null, "registration": "2004-05-26", "alias": [], "found": 0 },
{ "input": "nope", "error": { "type": "ValidationError", "message": "Invalid email \"nope\": expected local@domain" } }
]
}
Row error.typeMeaningCountedWhat to do
ValidationErrorNot an email addressYesFix or remove the record
InternalServerErrorThe check could not run for this addressNoSend it again later

When the whole request fails, the status code says why:

Statuserror.typeMeaning
403AuthorizationErrorYour plan has no bulk checks. They need Premium
422ValidationErrorThe body is wrong: emails must be 1 to 50 strings of at most 254 characters
429RateLimitErrorToo fast for your plan. Wait Retry-After seconds and send the batch again
429QuotaExceededErrorThe batch doesn't fit what is left of your quota. Nothing was counted

Quota​

  • Each address counts as one check, the same as a single check. A batch of 50 uses 50.
  • If the batch doesn't fit what is left, it is refused as a whole and nothing is counted. Send a smaller batch or wait for the reset.
  • Addresses the check could not complete (InternalServerError rows) are not counted.
  • Premium has 100,000 checks a month, so a list of 300,000 users takes three months of Premium. The command resumes where it stopped each month.

Large lists: Enterprise​

For more than 100,000 users, or more than 100,000 checks a month, Enterprise adds bulk credits that never expire to Premium:

  • Bulk requests use the credits first, so your monthly quota stays free for live signups.
  • Single /v1/check calls never use bulk credits.
  • GET /v1/usage shows the credits left in bulk_credits.

Enterprise is invoiced. Write to support@signitize.io with the size of your list.

Next steps​

  • Store email_normalized in a unique column and check new signups with POST /v1/check, so the list stays clean.
  • Never block a signup: keep new signups working when a check fails.