Om zakelijke e-mailadressen te vinden met Python stuur je de naam en bedrijfsgegevens van een persoon, of een openbare LinkedIn-profiel-URL, via de Requests-library naar Datablists Waterfall Email Finder API. De API retourneert het gevonden zakelijke e-mailadres, de deliverability-status van het adres en de mailprovider.

In het volledige voorbeeld hieronder zoeken we Satya Nadella bij microsoft.com en Reid Hoffman bij greylock.com op. Het script wacht tot de achtergrondtaak is voltooid en haalt alle resultaatpagina’s op. Daarna gebruiken we die resultaten om lokaal een lijst met geverifieerde contacten klaar te zetten voor campagnereview.

📌 Samenvatting voor wie haast heeft

Gebruik één Python-functie om bekende contacten naar de Waterfall Email Finder API te sturen, wacht tot de taak is afgerond en verzamel de gevonden zakelijke e-mailadressen. Zet vervolgens de geverifieerde contacten klaar voor campagnereview, terwijl onopgeloste contacten in je bronlijst blijven staan.

  • Input: Voor- en achternaam met een bedrijfsdomein, een volledige naam met een bedrijfsnaam of een openbare LinkedIn-profiel-URL.
  • Output: Een zakelijk e-mailadres met emailStatus en mxProvider, gevolgd door een lokale reviewlijst met alleen contacten waarvoor een e-mailadres is gevonden.

💡 Liever een no-code oplossing? Gebruik Datablists Waterfall Email Finder om zonder code zakelijke e-mailadressen uit een collectie te vinden.

Python, Requests en je API-key instellen

Voor dit Python-voorbeeld gebruiken we het package requests. Maak een bestand met de naam find_work_emails.py en installeer daarna Requests:

shell
python -m pip install requests

Maak een Personal API Key aan via je Datablist API-accountpagina. Voor toegang tot de REST API heb je het Growth-plan nodig. Exporteer de key in de terminal waarin je het script gaat uitvoeren:

shell
export DATABLIST_API_KEY="your-api-key"

Voor succesvolle resultaten van de Waterfall Email Finder worden ook credits gebruikt. In het onderdeel over kosten hieronder behandelen we die credits apart van het abonnement dat API-toegang biedt.

Zakelijke e-mails vinden met één Python-functie

Plak het volgende volledige script in find_work_emails.py:

python
import json
import os
import time
import uuid
import requests
def find_emails(people, api_key, settings):
"""Submit one email-finder task, wait, and return every result."""
tasks_url = "https://api.datablist.com/v1/enrichments/tasks"
headers = {"X-API-Key": api_key}
unique_id = str(uuid.uuid4())
print(f"Task uniqueId: {unique_id}", flush=True)
payload = {
"enrichmentId": "waterfall-email-finder",
"uniqueId": unique_id,
"settings": settings,
"inputs": people,
}
response = requests.post(tasks_url, headers=headers, json=payload)
response.raise_for_status()
task = response.json()
task_id = task["@id"]
task_url = f"{tasks_url}/{task_id}"
while task["status"] not in ("completed", "failed", "stopped"):
time.sleep(3)
response = requests.get(task_url, headers=headers)
response.raise_for_status()
task = response.json()
if task["status"] != "completed":
raise RuntimeError(
f"Task {task_id} {task['status']}: {task.get('error')}"
)
results = []
results_url = f"{task_url}/results"
params = {"limit": 100}
while True:
response = requests.get(results_url, headers=headers, params=params)
response.raise_for_status()
page = response.json()
results.extend(page["results"])
next_cursor = page["nextCursor"]
if next_cursor is None:
break
params["cursor"] = next_cursor
return results
if __name__ == "__main__":
api_key = os.environ.get("DATABLIST_API_KEY")
if not api_key:
raise RuntimeError("Set DATABLIST_API_KEY before running this script.")
settings = {"sourceKind": "name_company"}
people = [
{
"inputId": "contact-satya-nadella",
"data": {
"firstName": "Satya",
"lastName": "Nadella",
"companyNameOrDomain": "microsoft.com",
},
},
{
"inputId": "contact-reid-hoffman",
"data": {
"firstName": "Reid",
"lastName": "Hoffman",
"companyNameOrDomain": "greylock.com",
},
},
]
lookup_results = find_emails(people, api_key, settings)
for result in lookup_results:
print(json.dumps(result, indent=2))

Voer het uit vanuit dezelfde terminal:

shell
python find_work_emails.py

Je kunt ook het onderhouden Requests-voorbeeld downloaden. Zodra de blocking variant duidelijk is, vind je in de repository ook een asynchroon HTTPX-alternatief.

De functie voert achtereenvolgens drie soorten calls uit.

Eerst wordt de taak ingediend. Elke inputId is je vaste contact-ID. Het geneste data-object bevat de velden die voor de lookup worden gebruikt. De POST-call retourneert 202 Accepted met @id: de taak-ID die bij latere calls wordt gebruikt. De code toont vóór het indienen de uniqueId, zodat je ook een herstelwaarde hebt als de response verloren gaat.

Daarna wordt de taak gepolld. Datablist verwerkt de taak op de achtergrond. Deze Requests-client wacht en controleert de taak elke drie seconden, totdat de status completed, failed of stopped is. Requests blokkeert tijdens het wachten, maar de API-taak zelf blijft asynchroon.

Tot slot worden de resultaten opgehaald. Een taak kan meerdere resultaatpagina’s hebben. De loop blijft pagina’s ophalen totdat nextCursor null is. Gebruik inputId en niet de volgorde van de response om elk resultaat aan het juiste broncontact te koppelen.

Kies de juiste input voor je contactgegevens

Eén taak gebruikt één inputmodus. Behoud dezelfde functie find_emails() en vervang de waarden van settings en people door de route die bij je brongegevens past.

Kies een inputId die binnen de taak uniek is en waar mogelijk al bij het broncontact hoort. Een CRM-record-ID of andere duurzame lead-ID werkt goed. Datablist retourneert deze waarde bij het resultaat, zodat je records kunt koppelen zonder namen te vergelijken of ervan uit te gaan dat de response dezelfde volgorde heeft als de input.

Heb je aparte naamvelden en een bedrijfsdomein, gebruik dan sourceKind: "name_company". Een bekend domein is de duidelijkste identificatie van een bedrijf:

python
settings = {"sourceKind": "name_company"}
people = [
{
"inputId": "contact-satya-nadella",
"data": {
"firstName": "Satya",
"lastName": "Nadella",
"companyNameOrDomain": "microsoft.com",
},
}
]
lookup_results = find_emails(people, api_key, settings)

Heeft je bron één naamveld en een bedrijfsnaam, schakel dan useFullName in:

python
settings = {"sourceKind": "name_company", "useFullName": True}
people = [
{
"inputId": "contact-satya-nadella",
"data": {
"fullName": "Satya Nadella",
"companyNameOrDomain": "Microsoft",
},
}
]
lookup_results = find_emails(people, api_key, settings)

Heb je een URL van een openbaar persoonsprofiel, gebruik dan de LinkedIn-route:

python
settings = {"sourceKind": "linkedin"}
people = [
{
"inputId": "contact-satya-nadella",
"data": {
"linkedInProfile": "https://www.linkedin.com/in/satyanadella/"
},
}
]
lookup_results = find_emails(people, api_key, settings)

Deze route accepteert een openbare profiel-URL in de vorm linkedin.com/in/... als context over de persoon voor de e-mailzoekopdracht. Sales Navigator-profiel-URL’s worden niet geaccepteerd.

Wil je zelf provider-keys en de volgorde daarvan bepalen, lees dan de handleiding voor een custom waterfall. Voor de managed waterfall in dit artikel hoef je niets per provider in te stellen.

Zo vindt de managed waterfall een e-mailadres

Bij een aanvraag met naam en bedrijf gebruikt de API een opgegeven domein rechtstreeks. Geef je een bedrijfsnaam op, dan probeert de API die naam eerst aan een bruikbaar bedrijfsdomein te koppelen. Bij een LinkedIn-aanvraag schoont de API de openbare profiel-URL op en zet hij de beschikbare persoons- en bedrijfsgegevens om in de context die geschikte e-mailproviders nodig hebben.

De managed waterfall stuurt een onopgelost contact naar een geschikte provider. Komt daar geen bruikbaar e-mailadres uit, dan kan een andere geschikte provider hetzelfde contact proberen. Voor dat contact stopt de reeks zodra een zakelijk e-mailadres wordt geaccepteerd. In de standaardresponse staat niet welke finder is gebruikt.

Waarom een waterfall helpt bij internationale outreach

Providers van zakelijke e-mailadressen gebruiken verschillende datasets. Hun dekking verschilt daardoor per land en markt. Een provider vindt misschien niets voor een contact in een bepaalde regio, terwijl een andere provider wel over de benodigde gegevens beschikt.

Voor een sales- of growthteam geeft de waterfall elk onopgelost contact nog een kans om gevonden te worden voordat het buiten de outreachlijst valt. Zo kun je contacten terugvinden die je met een workflow met één provider zou missen, terwijl het technische proces voor het team consistent blijft.

Datablist beheert de volgorde van geschikte providers achter één API-integratie. Je dient een contact één keer in en ontvangt één resultaatformaat, in plaats van voor elke provider een aparte integratie te bouwen en te onderhouden en alle responses zelf samen te voegen.

Een zoekopdracht naar een zakelijk e-mailadres gaat na een resultaatloze poging door naar een andere provider en stopt zodra een e-mailadres is gevonden
Een zoekopdracht naar een zakelijk e-mailadres gaat na een resultaatloze poging door naar een andere provider en stopt zodra een e-mailadres is gevonden

Volledige resultaten uitlezen

De voorbeeldtaak leverde twee succesvolle resultaten op. De e-mailadressen zijn hieronder afgeschermd.

json
{
"taskId": "2286103ce43748828e27ce71b9cc526b",
"results": [
{
"inputId": "contact-satya-nadella",
"status": "success",
"outputs": {
"gender": null,
"mxProvider": "microsoft",
"emailFound": "s*******@microsoft.com",
"emailStatus": "verified"
},
"creditsUsed": "25",
"error": null
},
{
"inputId": "contact-reid-hoffman",
"status": "success",
"outputs": {
"gender": null,
"mxProvider": "mimecast",
"emailFound": "r*******@greylock.com",
"emailStatus": "verified"
},
"creditsUsed": "25",
"error": null
}
],
"nextCursor": null
}

emailFound is het geretourneerde zakelijke e-mailadres. emailStatus beschrijft de deliverability op het moment van de lookup en mxProvider vermeldt, indien beschikbaar, de hostingprovider voor e-mail. Beide records zijn verified en gebruikten elk 25 credits.

De campagnecode hieronder plaatst verified resultaten in campaign_contacts en zet andere gevonden adressen in needs_verification. De waarde creditsUsed is leidend voor de kosten van elk resultaat.

Het standaardresultaat van de managed waterfall bevat geen finderProvider. Dat veld is conditionele output voor een geldige custom-key-workflow met naam en bedrijf. Het script mag dit dus niet afleiden uit mxProvider.

Gevonden e-mails voorbereiden voor campagnereview

Zodra de directe lookup werkt, voeg je dit blok onderaan het script toe, nadat lookup_results is geretourneerd. Hiermee maak je op basis van de uitgevoerde lookup lokaal contacten klaar voor campagnereview.

python
results_by_id = {result["inputId"]: result for result in lookup_results}
campaign_contacts = []
needs_verification = []
for person in people:
result = results_by_id.get(person["inputId"])
if result is None:
continue
if result["status"] != "success":
continue
if not result["outputs"].get("emailFound"):
continue
contact = person.copy()
contact["result"] = result
if result["outputs"].get("emailStatus") == "verified":
campaign_contacts.append(contact)
else:
needs_verification.append(contact)
print(json.dumps({
"campaign_contacts": campaign_contacts,
"needs_verification": needs_verification,
}, indent=2))

Dankzij results_by_id maakt de volgorde van de response niet uit. Voor Satya leest de loop contact-satya-nadella uit de oorspronkelijke lijst people, zoekt hij het resultaat met dezelfde inputId, kopieert hij het bronrecord en voegt hij het volledige API-object toe onder result. Omdat het adres aanwezig is en de status verified is, komt het contact in campaign_contacts. Reid doorloopt hetzelfde pad, ook als zijn API-resultaat als eerste binnenkomt.

De drie voorwaarden houden de beslislogica overzichtelijk. De eerste slaat een contact over als er geen overeenkomend resultaat is geretourneerd. De tweede negeert fouten op rijniveau en andere statussen dan success. De derde vereist dat emailFound daadwerkelijk een waarde bevat. Door het volledige result-object toe te voegen, blijven de status, output, het creditverbruik en het foutveld beschikbaar voor latere controle.

Een gevonden e-mailadres met een andere deliverability-status gaat naar needs_verification. Een ontbrekend resultaat, een fout op rijniveau of een resultaat zonder emailFound komt in geen van beide voorbereide lijsten terecht. De oorspronkelijke lijst people blijft beschikbaar voor correcties of later onderzoek.

Kosten van de Waterfall Email Finder API berekenen

De standaard managed waterfall gebruikt 25 credits per gevonden zakelijk e-mailadres. Een mislukte standaardlookup gebruikt 0 credits. Lees creditsUsed uit elk resultaat in plaats van het totale aantal ingediende contacten te vermenigvuldigen.

Een gevonden e-mailadres met de status unverified gebruikt nog steeds 25 credits, ook al plaatst de lokale campagnecode het in needs_verification in plaats van campaign_contacts.

De twee gevonden e-mailadressen in dit voorbeeld gebruikten samen 50 credits. Voor je planning:

  • 100 gevonden zakelijke e-mailadressen gebruiken 2.500 credits.
  • 1.000 gevonden zakelijke e-mailadressen gebruiken 25.000 credits.
  • Een grotere inputlijst kan minder credits gebruiken dan contacten × 25, omdat lookups zonder resultaat niet in rekening worden gebracht.

Voor toegang tot de REST API heb je het Growth-plan nodig. Tegen het huidige opwaardeertarief in USD koop je voor $20 20.000 credits, oftewel $0,001 per credit. Bij dat tarief vertegenwoordigen 25.000 credits een waarde van $25. Het abonnement staat los van deze creditberekening. Bekijk de prijspagina van Datablist voor actuele informatie over plannen en pakketten.

Loading pricing…

Veelvoorkomende fouten oplossen en taken herstellen

De API-key ontbreekt. Het script geeft de fout Set DATABLIST_API_KEY before running this script. voordat er een request wordt verstuurd. Exporteer de variabele in de huidige terminal en voer het bestand opnieuw uit.

De API retourneert een authenticatiefout. raise_for_status() meldt de HTTP-fout. Kopieer een actuele Personal API Key, controleer of de header X-API-Key deze key gebruikt en voer het script pas opnieuw uit nadat je de inloggegevens hebt gecorrigeerd.

Het account heeft onvoldoende credits. Controleer het accountsaldo. Voeg credits toe of wacht op de volgende credittoewijzing van het plan voordat je meer werk indient.

De inputvelden passen niet bij de geselecteerde modus. Gebruik aparte naamvelden of fullName met name_company, of gebruik linkedInProfile met linkedin. Corrigeer het contact en dien het opnieuw in met één consistente modus.

De taak heeft de status failed of stopped. Het script geeft een RuntimeError met de taak-ID, eindstatus en beschikbare foutmelding van de taak. Controleer die taak en eventuele beschikbare resultaten voordat je bepaalt voor welke contacten nog een lookup nodig is.

De POST-response is verloren gegaan. Kopieer de uniqueId die vóór het indienen is getoond. Vraag met dezelfde key je takenlijst op:

shell
curl "https://api.datablist.com/v1/enrichments/tasks" \
-H "X-API-Key: $DATABLIST_API_KEY"

Zoek de taak met de getoonde uniqueId, kopieer de bijbehorende @id en ga verder via de URL voor de taakstatus of resultaten. Zo herstel je de bestaande taak in plaats van de contacten automatisch opnieuw in te dienen. De documentatie van de task API beschrijft de lifecycle en resultaatendpoints.

Volgende stappen

Je hebt nu één blocking Python Requests-functie voor de drie ondersteunde inputroutes en een lokaal filter dat gevonden, geverifieerde e-mailadressen klaarzet voor campagnereview.

Vervang de twee voorbeeldcontacten door een kleine selectie uit je eigen onderzochte contacten. Kies de inputroute die bij je gegevens past, voer de lookup uit en controleer emailStatus voordat je een adres gebruikt. Lees voor een workflow met grotere lijsten hoe je op grote schaal e-mailadressen vindt. De onderhouden GitHub-repository bevat downloadbare blocking en asynchrone Python-voorbeelden.