Real-time email validation on sign-up forms: how it works and what it catches
Real-time email validation checks an address as it is typed: syntax, typos, disposable domains, role accounts, MX and an optional mailbox check. Here is how it works.
Three ways to verify emails in Google Sheets compared, then a full Apps Script custom function with caching, the formulas to use it, formatting tips and when to switch to a bulk job.
You can verify emails in Google Sheets in three ways: a custom function written in Apps Script that calls a verification API from a cell, a Zapier or Make scenario that verifies each new row, or an export to a bulk verifier and an import of the results. For a few hundred addresses the Apps Script function is the quickest, with a formula like =VERIFYRE(A2) returning deliverable, undeliverable, risky or unknown right in the sheet.
| Method | Best for | Cost | Speed | Limits |
|---|---|---|---|---|
| Apps Script custom function | Ad hoc checks, lists under a few thousand rows, analysts who live in Sheets | One credit per unique address; repeats within 24 hours free | 0.5 to 3 seconds per address, batches run in one call | Apps Script URL fetch quota (20,000 calls a day on consumer accounts, 100,000 on Workspace) and 30 seconds per custom function call |
| Zapier or Make per row | Sheets that receive new rows continuously (form responses, lead capture) | One credit plus one Zapier task or Make operation per row | Seconds after the row appears | Each row is a billable task; bulk backfills get expensive |
| Export and bulk verify | Lists of thousands to 50,000 rows, one-off cleans | One credit per unique address | A few minutes for most files | Results come back as a file to re-import, not live in the sheet |
The rule of thumb: under about 2,000 rows, use the function. Rows arriving one at a time, use the automation. Anything larger or a one-off clean, use a bulk job.
vfy_live_.VERIFYRE_KEY, value your key. Keeping it here rather than in the code means it never ends up in a shared copy of the sheet./**
* Verify an email address with Verifyre.
* @param {string|string[][]} input A cell or range of addresses.
* @param {string} field Optional: "status" (default), "score", "reason", "did_you_mean" or "provider".
* @return The requested field for each address.
* @customfunction
*/
function VERIFYRE(input, field) {
field = (field || "status").toLowerCase();
if (Array.isArray(input)) {
return input.map(function (row) {
return row.map(function (cell) { return verifyOne_(cell, field); });
});
}
return verifyOne_(input, field);
}
function verifyOne_(email, field) {
email = String(email || "").trim().toLowerCase();
if (!email) return "";
var cache = CacheService.getScriptCache();
var cacheKey = "vfy:" + email;
var hit = cache.get(cacheKey);
var data = hit ? JSON.parse(hit) : null;
if (!data) {
var key = PropertiesService.getScriptProperties().getProperty("VERIFYRE_KEY");
if (!key) return "missing VERIFYRE_KEY";
var res = UrlFetchApp.fetch(
"https://verifyre.co/api/v1/verify?email=" + encodeURIComponent(email),
{ headers: { Authorization: "Bearer " + key }, muteHttpExceptions: true }
);
var code = res.getResponseCode();
if (code === 402) return "out of credits";
if (code === 429) return "rate limited, retry";
if (code !== 200) return "error " + code;
data = JSON.parse(res.getContentText());
cache.put(cacheKey, JSON.stringify(data), 21600); // 6 hours
}
var value = data[field];
return value === undefined || value === null ? "" : value;
}
=VERIFYRE(A2) in B2.The cache is the important detail. Sheets recalculates custom functions more often than you expect (on every edit to a referenced cell, on reopen, sometimes on a timer), and without the 6 hour CacheService entry every recalculation would call the API again. With it, a sheet of 1,000 addresses costs 1,000 credits the first time and nothing on recalculation. On Verifyre's side, repeat checks of the same address within 24 hours are also free and return cached: true, so even a cache miss after 6 hours is not billed.
=VERIFYRE(A2) status: deliverable, undeliverable, risky, unknown
=VERIFYRE(A2, "score") 0 to 100
=VERIFYRE(A2, "reason") short reason code
=VERIFYRE(A2, "did_you_mean") suggested correction for typos, blank if none
=VERIFYRE(A2:A500) a whole column in one call, fills down automatically
=IF(VERIFYRE(A2, "score") >= 90, "send", "hold")
=IF(VERIFYRE(A2, "did_you_mean") <> "", VERIFYRE(A2, "did_you_mean"), A2)
=COUNTIF(B2:B500, "deliverable")
=FILTER(A2:C500, B2:B500 = "undeliverable")
The range form =VERIFYRE(A2:A500) is better than filling a single-cell formula down, because Sheets makes one script call instead of 499, and the whole batch finishes well inside the 30 second limit at typical speeds. For more than roughly 500 rows, split the range into blocks of 300 to 500 so no single call risks the limit.
Conditional formatting makes the result readable at a glance: select column B, Format > Conditional formatting, text is exactly "undeliverable" fills red, "risky" fills amber, "deliverable" fills green. A FILTER in a second tab gives you an export-ready suppression list that updates itself.
The custom function is a convenience, not a pipeline. Switch to a bulk job when:
Export the column as CSV, upload it to the bulk email verifier, and import the results sheet back; jobs take up to 50,000 addresses. For a sheet that receives new rows all day from a form, an automation is the better fit, and verifying emails with Zapier or Make walks through that. Developers who want the same function inside a larger system should look at the email verification API directly, or the ready-made Google Sheets integration, which installs the function without pasting code.
Not with the cache in place. Results are held for 6 hours in CacheService, and Verifyre does not charge for repeat checks of the same address within 24 hours, so recalculation is free.
No. Verification is an SMTP conversation that stops before any message is sent, so the mailbox owner sees nothing.
Each custom function call has a 30 second limit, and a few hundred addresses on slow or greylisting servers can approach it. Split large ranges into blocks of 300 to 500 rows, or move to a bulk job.
Yes, if the key is in Script Properties. Anyone with edit access to the script can still read it, so share the sheet as view-only or give collaborators their own key.
Related reading
@Real-time email validation checks an address as it is typed: syntax, typos, disposable domains, role accounts, MX and an optional mailbox check. Here is how it works.
@Sender reputation explained: what Gmail and Yahoo measure, the February 2024 bulk sender rules one by one, how bounces and complaints feed it, and a 30-day recovery plan.
@Verify every lead with one HTTP step: Webhooks by Zapier GET plus a Filter, or Make's HTTP module plus a Router. Exact settings, typo fixing, error handling, costs and a Zapier vs Make comparison.
Photos: Freepik