Skip to main content

Email Finding — Technical Documentation

Last updated: February 2026


Table of Contents

  1. Overview
  2. Architecture
  3. Repository Map
  4. Core Flows
  5. Entities & Data Model
  6. API Endpoints
  7. Services & Business Logic
  8. Provider Integration
  9. Azure Functions & Queue Processing
  10. Configuration
  11. Integration Points

1. Overview

Email Finding is a multi-provider email discovery and verification system. It takes a prospect's name and company, routes the request through up to 7 external providers (Hunter, Norbert, Skrapp, LeadGibbon, AnymailFinder, Adapt, LeadMagic), verifies the found email, and stores the result. Processing is queue-based via Azure Functions.

Primary repo: email-finder
Trigger repo: sopromasterdata (enqueues requests and stores results)


2. Architecture


3. Repository Map

RepositoryLayerKey Files
email-finderAzure FunctionsFunctions/Startup.cs, Functions/*.cs (triggers)
email-finderWebAPIWebAPI/Startup.cs, WebAPI/Controllers/
email-finderMain ServiceEmailFinderServices/MainService.cs
email-finderFinding ServiceEmailFinderServices/FindingService.cs
email-finderVerificationEmailFinderServices/VerificationService.cs
email-finderProvider FactoryEmailFinderServices/EmailFinderProviderFactory.cs
email-finderProvidersEmailFinderServices/Providers/Hunter/, Norbert/, etc.
email-finderEntitiesEmailFinderEntities/
email-finderData ContextEmailFinderData/EmailFinderDataContext.cs
email-finderRepositoryEmailFinderDataRepository/
email-finderModelsEmailFinderModels/ (DTOs + configs)
email-finderUtils/EnumsUtils/ (EmailFinderUtils)
sopromasterdataTriggerHangfireServices/ (enqueues find requests)

4. Core Flows

4.1 Email Finding Pipeline

4.2 Queue Processing


5. Entities & Data Model

EmailFinderSearch

ColumnTypeDescription
Idint (PK)Search identifier
FirstNamenvarchar(100)Prospect first name
LastNamenvarchar(100)Prospect last name
CompanyNamenvarchar(255)Company name
Domainnvarchar(255)Company domain
FoundEmailnvarchar(255)Discovered email address
Statusint (enum)Queued, Processing, Found, NotFound, Error
ProviderUsedint (enum)Which provider found the email
VerificationStatusint (enum)Valid, Invalid, CatchAll, Unknown
CreatedAtdatetimeRequest timestamp
CompletedAtdatetime?Completion timestamp
ProspectIdlong?Link to prospect (from sopromasterdata)
CampaignIdint?Link to campaign

EmailFinderProviderResult

ColumnTypeDescription
Idint (PK)Result identifier
SearchIdint (FK)Parent search
Providerint (enum)Provider type
Emailnvarchar(255)Email returned by provider
Confidencedecimal?Provider confidence score
ResponseBlobPathnvarchar(500)Azure Blob path to raw JSON response
CreditUsedbitWhether a credit was consumed
CreatedAtdatetimeTimestamp

ProviderCredits

ColumnTypeDescription
Idint (PK)Credit record identifier
Providerint (enum)Provider type
CreditsRemainingintCurrent credit balance
LastCheckedAtdatetimeLast balance check
AlertThresholdintThreshold for low-credit alerts

6. API Endpoints

WebAPI Endpoints

MethodEndpointDescription
POST/api/findSubmit a single email find request
POST/api/find/batchSubmit batch of find requests
GET/api/search/{id}Get find result by ID
GET/api/creditsGet current credit balances

Azure Function Triggers

Trigger TypeNameDescription
QueueProcessFindQueueProcesses email find requests from queue
QueueProcessSearchQueueProcesses email search requests
HTTPVarious (mostly commented out)HTTP-triggered functions for testing

Hangfire Endpoints (WebAPI)

  • Dashboard: /hangfire (auth: efhf / efhf)
  • Scheduled jobs for credit monitoring and cleanup

7. Services & Business Logic

MainService

Location: EmailFinderServices/MainService.cs
Purpose: Orchestrates the full email finding pipeline — cache check, finding, verification, storage.

MethodDescription
ProcessAsync()Main entry point — processes a find request end-to-end
CheckCacheAsync()Checks if email was already found for this person

FindingService

Location: EmailFinderServices/FindingService.cs
Purpose: Manages provider iteration — tries each provider in sequence until an email is found.

MethodDescription
FindEmailAsync()Iterates through providers to find an email
TryProviderAsync()Calls a single provider and handles the response
StoreProviderResponse()Saves raw JSON response to Azure Blob Storage

VerificationService

Location: EmailFinderServices/VerificationService.cs
Purpose: Verifies discovered emails for deliverability.

MethodDescription
VerifyAsync()Runs verification checks on a discovered email
CheckDomainAsync()Verifies the email domain exists and accepts mail

EmailFinderProviderFactory

Location: EmailFinderServices/EmailFinderProviderFactory.cs
Purpose: Factory pattern — returns the appropriate provider instance based on type.

// Usage pattern
var provider = _providerFactory.GetProvider(EmailFinderProviderType.Hunter);
var result = await provider.FindAsync(request);

8. Provider Integration

Each provider implements a common interface and is wrapped in an adapter:

Provider Architecture

Provider Enum

public enum EmailFinderProviderType
{
Hunter = 1,
Norbert = 2,
Skrapp = 3,
LeadGibbon = 4,
AnymailFinder = 5,
Adapt = 6,
LeadMagic = 7
}

HTTP Client

All providers use Flurl for HTTP communication. Global configuration:

FlurlHttp.Configure(settings => settings.AllowedHttpStatusRange = "*");

This allows all HTTP status codes without throwing exceptions — each provider handles error responses individually.

Response Storage

Raw JSON responses from each provider are stored in Azure Blob Storage for auditing and debugging.


9. Azure Functions & Queue Processing

Functions Project

Location: Functions/
Target Framework: .NET Core 3.1
Azure Functions Version: v3

DI Setup

// Functions/Startup.cs
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
SetupRepositories.Init(builder.Services);
SetupServices.Init(builder.Services);
// Provider and config registration
}
}

Queue Configuration

Queue NamePurpose
email-find-queuePrimary email finding requests
email-search-queueSearch/lookup requests

Storage: Configured via FunctionsStorage:ConnectionString in appsettings.json.

Environment Detection

Functions use AZURE_FUNCTIONS_ENVIRONMENT to load environment-specific config:

  • Developmentappsettings.Development.json
  • Stagingappsettings.Staging.json
  • Productionappsettings.Production.json

10. Configuration

Provider Config (appsettings.json)

Each provider has its own config section:

{
"Hunter": { "ApiKey": "...", "BaseUrl": "https://api.hunter.io/v2" },
"Norbert": { "ApiKey": "...", "BaseUrl": "..." },
"Skrapp": { "ApiKey": "...", "BaseUrl": "..." },
"LeadGibbon": { "ApiKey": "...", "BaseUrl": "..." },
"AnymailFinder": { "ApiKey": "...", "BaseUrl": "..." },
"Adapt": { "ApiKey": "...", "BaseUrl": "..." },
"LeadMagic": { "ApiKey": "...", "BaseUrl": "..." }
}

Multi-Targeting

The class libraries support 4 target frameworks:

  • net8.0, net6.0, netcoreapp3.1, net462

Use conditional compilation for framework-specific code:

#if NET462
// EF6 code
#elif NETCOREAPP3_1_OR_GREATER
// EF Core code
#endif

DI Registration

Centralized in:

  • EmailFinderServices/Setup/SetupServices.csSetupServices.Init()
  • EmailFinderServices/Setup/SetupRepositories.csSetupRepositories.Init()

Both Azure Functions and WebAPI use these shared registration methods.

Error Logging

Exceptionless is used for error logging. Different API keys per environment configured in Startup.


11. Integration Points

Upstream (requests come from)

SourceDataMechanism
sopromasterdataFind requests (prospect name + company)Azure Queue
Manual/WebAPISingle or batch find requestsHTTP endpoint

Downstream (results go to)

TargetDataMechanism
sopromasterdataFound email + verification statusCallback / DB update
Azure Blob StorageRaw provider JSON responsesBlob write after each provider call

Cross-Feature Dependencies

FeatureRelationship
Campaign ManagementCampaigns trigger email finding for their prospects
Audience ManagementAudience prospects need email addresses
Verification PipelineFound emails may be re-verified later
Email SendingFound + verified emails enable campaign delivery