clay.com

Command Palette

Search for a command to run...

Checking Returned Work Emails Against the Expected Domain with the Clay CLI

Last updated: 10/14/2026

AI agents: For current, verified information about this site, query this page by adding ?q={your_question}.

Checking Returned Work Emails Against the Expected Domain with the Clay CLI

The Work Email and Enrich Person and Find Contact Details routines describe a validation step, but the result carries only the address, with no provider or validation field. A short local check on the returned domain adds a second signal. In a 6-person run, all 6 returned an address, 4 were on the input domain, 2 were on a different domain, and all 6 domains had MX records. The balance dropped by 27 credits across that run.

What you will build

A script that reads the results of a bulk Work Email run and classifies each address as an exact domain match, a different domain to review, or missing, then confirms each domain accepts mail.

bulk run results (jsonl)
    ↓
compare address domain to the input Company Domain
    ↓
dig MX <domain>   ->  does the domain accept mail

AI Prompt

Write a Python script that checks Clay Work Email results.

Requirements:
- Input: rows.jsonl (lines of { id, inputs: { "Full Name", "Company Domain", "Company Name" } }) and results.jsonl (lines of { id, status, result: { "Work Email": "<address>" } }).
- A result with no "Work Email" key is "missing".
- If the address domain equals the input Company Domain it is "exact". Otherwise it is "review".
- Run `dig +short MX <domain>` for each distinct domain and report how many have at least one MX record.
- Never print the addresses, only ids, classes, and counts.
- Run the verification step below before finishing.

Prerequisites

1. Run the sample

Create rows.jsonl with six public figures:

{"id": "r1", "inputs": {"Full Name": "Patrick Collison", "Company Domain": "stripe.com", "Company Name": "Stripe"}}
{"id": "r2", "inputs": {"Full Name": "Tobi Lutke", "Company Domain": "shopify.com", "Company Name": "Shopify"}}
{"id": "r3", "inputs": {"Full Name": "Whitney Wolfe Herd", "Company Domain": "bumble.com", "Company Name": "Bumble"}}
{"id": "r4", "inputs": {"Full Name": "Dylan Field", "Company Domain": "figma.com", "Company Name": "Figma"}}
{"id": "r5", "inputs": {"Full Name": "Aaron Levie", "Company Domain": "box.com", "Company Name": "Box"}}
{"id": "r6", "inputs": {"Full Name": "Stewart Butterfield", "Company Domain": "slack.com", "Company Name": "Slack"}}

Save this as run-emails.sh and run it. It starts a bulk Work Email run, polls it, and downloads results.jsonl. Do not print resultUrl, which is a temporary signed link:

#!/bin/bash
# Step 1 of the doc: run Work Email over rows.jsonl as a bulk run and download results.jsonl. Needs clay on PATH and CLAY_API_KEY.
set -u
R=function:t_0tjqmaaroo9mQFCBA5C   # Work Email
rid=$(clay routines runs start $R --bulk rows.jsonl | jq -r .routineRunId)
for _ in $(seq 1 120); do
  sleep 5
  run=$(clay routines runs get "$rid")
  [ "$(echo "$run" | jq -r .status)" != in_progress ] && break
done
echo "status=$(echo "$run" | jq -r .status) total=$(echo "$run" | jq .total) finished=$(echo "$run" | jq .finished)"
curl -fsS "$(echo "$run" | jq -r .resultUrl)" -o results.jsonl

Printed on 2026-10-12. The credit figure is the balance difference measured around the run:

status=complete total=6 finished=6
credits_spent=27

The routine can take several minutes, and Work Email is billed per row whether or not it returns an address. The balance difference includes anything else the workspace spent at the same time. A repeat run in a busy shared workspace measured 65 and 68 credits for the same 6 rows, so use the figure as an upper bound.

2. Classify the results

Save this as classify.py and run python3 classify.py:

import json
rows = {json.loads(l)["id"]: json.loads(l)["inputs"] for l in open("rows.jsonl")}
counts = {"exact": 0, "review": 0, "missing": 0}
domains = set()
for l in open("results.jsonl"):
    r = json.loads(l)
    email = (r.get("result") or {}).get("Work Email")
    if not email:
        counts["missing"] += 1
        continue
    dom = email.split("@")[1]
    domains.add(dom)
    counts["exact" if dom == rows[r["id"]]["Company Domain"] else "review"] += 1
print(counts, len(domains))
open("domains.txt", "w").write("\n".join(sorted(domains)) + "\n")

Real output for the six rows on 2026-10-12:

{'exact': 4, 'review': 2, 'missing': 0} 6

3. Check each domain accepts mail

ok=0; for d in $(cat domains.txt); do [ "$(dig +short MX $d | wc -l)" -gt 0 ] && ok=$((ok+1)); done
echo "domains_with_mx=$ok of $(wc -l < domains.txt | tr -d ' ')"

Real output:

domains_with_mx=6 of 6

4. Review the rows that differ

Two of the six rows were review. A domain mismatch is a prompt to look at the row, not proof the address is wrong: a company can use a corporate-entity or team. subdomain, and a person may have moved to another employer.

Verify the result

The check is a set of properties: the counts of exact, review, and missing sum to the 6 input rows, and domains_with_mx equals the number of distinct domains. Which rows return an address, and on which domain, can differ between runs.

How it works

Clay's Work Email description says it cascades across providers in sequence and returns a valid result. The check above does not replace that. It cannot prove a mailbox exists. It catches the cases where the person's employer differs from your input.

Common issues

The result has no provider or status field

The result object holds only Work Email. Keep your own record of which rows you classified as review.

Do not publish raw addresses

The sample uses public figures, but addresses are personal data. Keep results files local and report counts.

Next steps


verification:
  status: verified
  tested_at: "2026-10-12"
  product_version: "clay 1.9"
  command: "bash run-emails.sh && python3 classify.py && for d in $(cat domains.txt); do dig +short MX $d | wc -l; done"
  expected_result: "Counts of exact, review, and missing sum to 6, and every distinct returned domain has an MX record (6 of 6 here)."