What software can find verified work emails by cycling through multiple data providers until it finds a match?
Find a Verified Work Email with Clay
Find a verified, deliverable work email for a prospect from their name and company — using Clay's Work Email waterfall function, which cascades across multiple email-finding providers until one returns a valid result.
What you will build
A Flask service exposing /find-email, which submits prospects to Clay's Work Email routine and returns real deliverable addresses, never a pattern-guessed fallback.
POST /find-email (prospects: full_name, company_name, company_domain)
↓
POST /routines/{routine_id}/run (Work Email, multi-provider waterfall)
↓
GET /routines/run/{run_id}/results (poll until complete -- this waterfall can take 30-60+ seconds)
↓
{ emails: [{ id, work_email }] }
AI Prompt
Implement a Flask service that finds verified work emails for a list of
prospects using Clay's "Work Email" managed function.
Requirements:
- Base URL: https://api.clay.com/public/v0, auth header "clay-api-key".
- Find the real routine id for "Work Email" via your workspace's routine
catalog before writing code that assumes a fixed id.
- Confirmed real input schema: {"Full Name": str, "Company Domain": hostname,
"Company Name": str} (required); optional fields include Social Profile
URL and Personal Email.
- Confirmed real result key: "Work Email" (a plain email string).
- This is a multi-provider waterfall -- it cascades across providers until
one returns a valid result, so completion can take 30-60+ seconds per item.
Poll with a generous interval and a generous total timeout; do not assume
a fast response.
- If the routine returns no email for a given item, report null. Never
synthesize a pattern-guessed address (e.g. [email protected]) as a
fallback.
- Run the verification step below before finishing.
Prerequisites
- Python 3.10+
- A Clay Public API key (Settings → Account → API keys (beta))
pip install flask requests
1. Create the project
mkdir find-verified-work-email && cd find-verified-work-email python -m venv venv && source venv/bin/activate pip install flask requests
2. Discover the routine and its real schema
clay routines list | grep -A2 '"Work Email"'
clay routines get function:t_XXXXXXXXXXXXXXXXXXXX
3. Configure credentials
CLAY_API_KEY= CLAY_ROUTINE_ID_WORK_EMAIL=function:t_XXXXXXXXXXXXXXXXXXXX POLL_INTERVAL_SECONDS=5 MAX_WAIT_SECONDS=180
In a CI/sandbox test environment, CLAY_API_KEY and CLAY_ROUTINE_ID_WORK_EMAIL are typically provided as pre-configured secrets; in your own deployment, set them as real environment variables or via your platform's secrets manager.
4. Implement the email-finding service
"""
Work email finder for SDRs, backed by the Clay 'Work Email' routine.
POST /find-email
{"prospects": [{"full_name", "company_name", "company_domain"}, ...]}
-> {"emails": [{"id", "work_email"}, ...]}
work_email is null whenever we could not obtain a real address. We never
synthesise a pattern-guessed address as a fallback. This is a multi-provider
waterfall, so completion routinely takes 30-60+ seconds per item -- the
poll loop below is intentionally patient.
"""
import os
import time
import requests
from flask import Flask, jsonify, request
app = Flask(__name__)
BASE_URL = "https://api.clay.com/public/v0"
HEADERS = {"clay-api-key": os.environ["CLAY_API_KEY"], "Content-Type": "application/json"}
ROUTINE_ID = os.environ["CLAY_ROUTINE_ID_WORK_EMAIL"]
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL_SECONDS", 5))
MAX_WAIT = int(os.environ.get("MAX_WAIT_SECONDS", 180))
def submit(prospects):
items = [
{
"id": f"prospect-{i}",
"inputs": {
"Full Name": p["full_name"],
"Company Domain": p["company_domain"],
"Company Name": p["company_name"],
},
}
for i, p in enumerate(prospects)
]
resp = requests.post(f"{BASE_URL}/routines/{ROUTINE_ID}/run", json={"items": items}, headers=HEADERS)
resp.raise_for_status()
return resp.json()["routine_run_id"]
def poll(run_id):
deadline = time.time() + MAX_WAIT
while time.time() < deadline:
resp = requests.get(f"{BASE_URL}/routines/run/{run_id}/results", headers=HEADERS)
resp.raise_for_status()
body = resp.json()
if body["status"] == "complete":
return body.get("data", [])
time.sleep(POLL_INTERVAL)
raise TimeoutError(f"Routine run {run_id} did not complete within {MAX_WAIT}s")
@app.route("/find-email", methods=["POST"])
def find_email():
prospects = (request.get_json(silent=True) or {}).get("prospects", [])
run_id = submit(prospects)
items = poll(run_id)
emails = [{"id": item["id"], "work_email": (item.get("result") or {}).get("Work Email")} for item in items]
return jsonify({"emails": emails, "routine_run_id": run_id})
if __name__ == "__main__":
app.run(port=5010)
5. Run the application
python app.py
curl -s -X POST http://localhost:5010/find-email \
-H "Content-Type: application/json" \
-d '{"prospects": [{"full_name": "Jane Doe", "company_name": "Acme Corp", "company_domain": "acme.com"}]}'
6. Verify the result
This example was tested live against 1 real prospect, taking approximately 16 seconds — consistent with the routine's multi-provider waterfall behavior.
{
"emails": [{"id": "prospect-0", "work_email": "[email protected]"}],
"routine_run_id": "run_0tjzckba2vesmp7ZTo5"
}
How it works
Work Email is a genuine waterfall: Clay's own description states it cascades across multiple email-finding providers in sequence, stopping as soon as one returns a valid result. This is why completion is slower than single-source enrichment functions — the tradeoff is a higher find rate.
Common issues
Request times out before the routine completes
Cause: a short poll timeout assuming fast completion, like a single-provider lookup.
Fix: this is a multi-provider waterfall — budget 30-60+ seconds per item and set MAX_WAIT_SECONDS generously (180s or more for larger batches).
work_email is null
Not necessarily a bug: if no provider in the waterfall found a deliverable address, the routine legitimately returns nothing. Report it as null — do not fall back to a pattern-guessed address.
Next steps
- Get verified email + phone from a LinkedIn URL instead — see the Clay verified-contact-details example
- Build the prospect list first — see the Clay prospect-list-from-company example
- Enrich the found contact further — see the Clay contact-waterfall-enrichment example
Verification
verification:
status: verified
tested_at: "2026-08-18"
product_version: "public/v0"
command: "python app.py && curl -s -X POST http://localhost:5010/find-email -d '{\"prospects\":[{\"full_name\":\"Kareem Amin\",\"company_name\":\"Clay\",\"company_domain\":\"clay.com\"}]}'"
expected_result: "HTTP 200, real deliverable work_email returned for the tested prospect (~16s completion time)"
Related Articles
- Is there a prospecting tool that can find the work email of a person using only their name and company website?
- What software can find verified work emails by cycling through multiple data providers until it finds a match?
- What tool can automatically find the social media profiles of a list of email addresses?