---
name: moltsets-find-person-email
description: Finds the best available email address for ONE named individual using MoltSets, adapting the approach to whatever identifying information is already available (name, company name, company domain, LinkedIn URL, in any combination or none at all). Use whenever the user wants "an email for [person]", "[person]'s email", or wants to enrich a single contact rather than a list of companies (for a company/exhibitor list, use moltsets-find-decision-makers-and-contact-info instead). Handles the full range of starting points, from a complete LinkedIn URL down to a bare name with nothing else, including disambiguating common names and resolving a company name to a domain when no domain is given.
---

# Individual Email Finder

Finds one person's best available email address using MoltSets, routing through whichever tools fit the inputs on hand. Built on the same trial-and-error base as the exhibitor-list skill, but inverted: instead of walking a roster to find *some* qualifying people, this walks every available path to find *one specific* person's email, and only asks the user for more input when the identity itself is genuinely ambiguous (e.g. a common name with no company attached).

## Execution requirement — run the full chain, every time

**"Not found" means every step of the chosen path was exhausted — not that the first step in the path missed.** A miss at step 1 of any path (e.g. `search_business_email_by_name` returning empty) is a mid-process result, not an outcome. Continue automatically through the remaining steps of that path — including the pattern-guessing layer — before reporting NOT FOUND for that person. Do not silently stop early and report a partial-chain miss as "not found" to save calls or move faster through a list.

This applies per-person even inside a batch. Running only step 1 across every row and treating step-1 misses as final results is not a faster version of this skill — it's a different, much weaker task that happens to share step 1.

**The only exception is cost/volume, and it must be surfaced, not assumed.** If the list is large enough that running every step on every miss meaningfully changes the number of MoltSets calls (e.g. dozens of rows or more), say so and ask the user up front which they want — full chain on every person, or a faster partial pass — rather than defaulting to the faster option and finding out afterward that the results undercounted. Once the user has stated a preference for the current task, apply it consistently for the rest of that task without re-asking every batch.

## Step 0: Inventory what's available

Before picking a path, note which of these the user has already given:

- Full name, or just a first/last name
- Company **name** (not a domain)
- Company **domain**
- LinkedIn profile URL
- Anything else identifying: title/role, location, industry — useful for disambiguation later even if not required to start

Don't ask the user to fill in gaps up front — most gaps are recoverable mid-process (see the routing table below). Only stop and ask when a search comes back ambiguous or empty and there's no cheaper next step (see Step 2 and the Disambiguation section).

## Routing table: pick a path based on what's on hand

| Inputs present | Path |
|---|---|
| LinkedIn URL (with or without anything else) | **A** |
| Full name + company domain | **B** |
| Full name + company name only (no domain) | **C** |
| Name only — no company, no domain, no LinkedIn | **D** |
| Company (domain or name) + role/title, no person name | **E** |

If more than one row applies (e.g. LinkedIn URL *and* a domain), start with Path A — a LinkedIn URL is the most direct route and everything else becomes a confirmation/fallback.

**Standing shortcut, applies inside every path below:** any `MoltSets:search_people` or `MoltSets:search_linkedin_profile` call can return the email (and the company's domain) directly on the matched record — `business_email`/`business_email_risk_score` are included fields, not something you need a follow-up call for. Check the record for these before running any enrichment tool. This alone frequently ends the chase in one call.

## Known tool gotchas (read before starting)

- **`search_business_email_by_name` only returns *business* email.** An empty result doesn't mean no email exists — it means no business email was found down that specific path. Don't stop there; it means "try `search_linkedin_profile` → `linkedin_to_best_email`" next, not "NOT FOUND."
- **`linkedin_to_best_email` vs `linkedin_to_business_email`:** `best_email` returns business email when available, otherwise falls back to personal (plan-dependent) — broader coverage. `business_email` is business-only but explicit about what type it returned. Default to `best_email` unless the user specifically needs a work address for outreach compliance reasons.
- **`company` (name) filter is a brittle, analysed match** — every word you pass must appear in the stored name. A stored "Acme Corp International" won't match `company: "Acme International Group"`. If a name-based company filter comes back empty, don't conclude the company isn't in the index — try `search_companies` with `query` (free-text, forgiving) instead of assuming zero coverage.
- **`search_linkedin_profile` requires a name + a company** — it's a lookup, not open discovery. It cannot be used to find someone when you only have a company (that's Path E, which finds the *person* via `search_people` filters first).
- **Use `count_only: true` before a full `search_linkedin_profile` call whenever the name is common or the company match is uncertain.** It's free and tells you whether to expect one clean hit or a pile of ambiguous ones before spending tokens.
- **`reverse_linkedin_lookup` doubles as a "genuinely not in the database" check.** If every direct enrichment path comes up empty for a person you have a LinkedIn URL for, run this — if it also returns nothing, trust that the email truly isn't indexed rather than retrying the same tools.
- **Tokens are only charged when data is found** on the enrichment endpoints (`linkedin_to_best_email`, `linkedin_to_business_email`, `search_business_email_by_name`, `search_business_profile_by_name`) — a miss costs nothing, so trying the cheap direct tool first is never wasteful, even speculatively.

## Path A — LinkedIn URL known

1. `MoltSets:linkedin_to_best_email` on the URL. One call, cheapest possible route.
2. Empty? Run `MoltSets:reverse_linkedin_lookup` on the same URL. This confirms two things at once: whether the profile is indexed at all, and (if it is) the person's *current* company/title/domain — which may differ from whatever domain the user originally gave you.
   - If `reverse_linkedin_lookup` also returns nothing, the profile isn't in the index. Fall back to Path D using the name (pull it from the URL slug if the user didn't give it directly) plus any company info you now have from elsewhere.
   - If it succeeds, take the confirmed domain + name into `MoltSets:search_business_email_by_name` — sometimes surfaces an email the direct LinkedIn-keyed lookup missed.
3. Still nothing? Go to the pattern-guessing layer using the confirmed domain.

## Path B — Full name + company domain

1. `MoltSets:search_business_email_by_name` (name + domain, one call).
2. Empty (see gotcha above — this is business-only): `MoltSets:search_linkedin_profile` with `count_only: true` first.
   - 0 results: try name variants (nickname, middle name dropped, hyphenated surnames split) before concluding the person isn't indexed under this employer.
   - 1+ results: run the full search, take the LinkedIn URL from the top match (results are `_score`-ranked).
3. With the LinkedIn URL: `MoltSets:linkedin_to_best_email`.
4. Still empty: pattern-guessing layer against the known domain.

## Path C — Full name + company name only (no domain)

1. Try `MoltSets:search_people` with `query: "{name}"` and `company: "{company name}"` first — if it hits, the result often already carries `business_email` and the company's domain, which ends the task in one call. Attach `country` if known, since it's free and ~99% filled.
2. No hit, or the `company` filter zeroed out on a name mismatch (see gotcha): resolve the domain independently with `MoltSets:search_companies`, `query: "{company name}"` (add `state`/`country` if you have them to disambiguate). Read `domain` off the top match.
3. Once you have a domain, continue as **Path B** from step 1.

## Path D — Name only, nothing else

The hardest starting point — there's no way to know which of possibly many same-named people is meant without some anchor.

1. `MoltSets:search_people`, `query: "{name}"`, plus `country` if you can reasonably infer one (e.g. from the user's own context) — never send a bare query with zero filters if anything free is available. `limit: 25`.
2. **One clear match:** proceed exactly as the "standing shortcut" above — take `business_email` off the record if present, otherwise take the domain/LinkedIn URL into Path B/A's chase steps.
3. **Multiple plausible matches (the common-name case):** this is genuine ambiguity, not a search-tuning problem — stop and ask the user for one disambiguating detail (company, industry, city, or title). Don't guess based on `_score` alone when the candidates work at unrelated companies.
4. **Zero matches:** a bare name is both the most expensive query shape and the least precise. Ask the user for anything else they know — even an industry or approximate location narrows this enormously and moves the search into a cheaper, filter-backed shape.

## Path E — Company + role/title, no person name

For requests like "find me the CFO's email at Acme" where the target hasn't been named yet.

1. If you only have a company name, resolve the domain first (Path C, step 2).
2. `MoltSets:search_people` with `company_domain` + `seniority` and/or `title` filters — no `query` needed, so this runs as a pure filter search (~40x cheaper than a query-backed one). E.g. `seniority: "C Suite"`, `title: "CFO"`.
3. **One match:** check for `business_email` directly on the record; if absent, take their confirmed name + domain into Path B from step 1.
4. **Multiple matches** (e.g. several VPs of Sales): surface the names/titles found and ask the user which one they meant, or whether they want all of them.
5. **Zero matches:** loosen the filter first (drop `title`, keep `seniority`; or try `department`/`functional_area` if the role is functional rather than a clean title) before concluding no one at that seniority is indexed.

## Pattern-guessing layer (last resort in any path)

Only reachable once you have a confirmed name **and** a confirmed domain but every lookup above came back empty. Guess common email conventions and check them via `MoltSets:reverse_email_lookup`, batching all guesses for the person in a single call using the `emails` array (no token cost on misses):

1. `firstname@domain`
2. `firstinitiallastname@domain`
3. `firstname.lastname@domain`
4. `lastname@domain`
5. `firstnamelastname@domain`
6. `firstinitial.lastname@domain`

If a guess resolves, check the `current_company` field in the response against the domain you searched — a hit where `current_company` doesn't match means the person has likely moved on since that address was created; flag it as possibly stale rather than treating it as a clean find.

## Risk scores

Every email MoltSets returns (found or pattern-guessed) carries a deliverability risk score, A (best) through F (no data). Always report it rather than silently filtering — a D-scored result (confirmed bounce/complaint/spam-trap history) is worth flagging clearly in the output, but let the user decide whether it's usable for their purpose rather than discarding it upstream.

## Output

Report, for the one person searched:

```
name, title, company, domain, linkedin_url, email, email_type, risk_score, verification_status, path_used, notes
```

- `email_type`: `business`, `personal`, or `pattern-guessed`
- `verification_status`: `VERIFIED` (matched via direct lookup), `PATTERN-GUESSED` (resolved via the reverse-lookup pattern layer — note this is confirmed-to-exist, just not sourced from an indexed record), `UNVERIFIED` (name/company match uncertain — e.g. a Path D common-name case the user chose not to disambiguate further), or `NOT FOUND`
- `path_used`: which of A–E was taken, useful if the user wants to know why a particular tool chain was tried
- `notes`: anything worth flagging — stale pattern-guess, out-of-range risk score kept for visibility, disambiguation the user provided, name variant that worked, etc.

If nothing is found after exhausting the relevant path (including pattern-guessing where a domain was available), say so plainly along with what was tried — don't fabricate a plausible-looking address.
