Email Finding — Technical Documentation
Last updated: February 2026
Table of Contents
- Overview
- Architecture
- Repository Map
- Core Flows
- Entities & Data Model
- API Endpoints
- Services & Business Logic
- Provider Integration
- Azure Functions & Queue Processing
- Configuration
- 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
| Repository | Layer | Key Files |
|---|---|---|
| email-finder | Azure Functions | Functions/Startup.cs, Functions/*.cs (triggers) |
| email-finder | WebAPI | WebAPI/Startup.cs, WebAPI/Controllers/ |
| email-finder | Main Service | EmailFinderServices/MainService.cs |
| email-finder | Finding Service | EmailFinderServices/FindingService.cs |
| email-finder | Verification | EmailFinderServices/VerificationService.cs |
| email-finder | Provider Factory | EmailFinderServices/EmailFinderProviderFactory.cs |
| email-finder | Providers | EmailFinderServices/Providers/Hunter/, Norbert/, etc. |
| email-finder | Entities | EmailFinderEntities/ |
| email-finder | Data Context | EmailFinderData/EmailFinderDataContext.cs |
| email-finder | Repository | EmailFinderDataRepository/ |
| email-finder | Models | EmailFinderModels/ (DTOs + configs) |
| email-finder | Utils/Enums | Utils/ (EmailFinderUtils) |
| sopromasterdata | Trigger | HangfireServices/ (enqueues find requests) |
4. Core Flows
4.1 Email Finding Pipeline
4.2 Queue Processing
5. Entities & Data Model
EmailFinderSearch
| Column | Type | Description |
|---|---|---|
Id | int (PK) | Search identifier |
FirstName | nvarchar(100) | Prospect first name |
LastName | nvarchar(100) | Prospect last name |
CompanyName | nvarchar(255) | Company name |
Domain | nvarchar(255) | Company domain |
FoundEmail | nvarchar(255) | Discovered email address |
Status | int (enum) | Queued, Processing, Found, NotFound, Error |
ProviderUsed | int (enum) | Which provider found the email |
VerificationStatus | int (enum) | Valid, Invalid, CatchAll, Unknown |
CreatedAt | datetime | Request timestamp |
CompletedAt | datetime? | Completion timestamp |
ProspectId | long? | Link to prospect (from sopromasterdata) |
CampaignId | int? | Link to campaign |
EmailFinderProviderResult
| Column | Type | Description |
|---|---|---|
Id | int (PK) | Result identifier |
SearchId | int (FK) | Parent search |
Provider | int (enum) | Provider type |
Email | nvarchar(255) | Email returned by provider |
Confidence | decimal? | Provider confidence score |
ResponseBlobPath | nvarchar(500) | Azure Blob path to raw JSON response |
CreditUsed | bit | Whether a credit was consumed |
CreatedAt | datetime | Timestamp |
ProviderCredits
| Column | Type | Description |
|---|---|---|
Id | int (PK) | Credit record identifier |
Provider | int (enum) | Provider type |
CreditsRemaining | int | Current credit balance |
LastCheckedAt | datetime | Last balance check |
AlertThreshold | int | Threshold for low-credit alerts |
6. API Endpoints
WebAPI Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST | /api/find | Submit a single email find request |
POST | /api/find/batch | Submit batch of find requests |
GET | /api/search/{id} | Get find result by ID |
GET | /api/credits | Get current credit balances |
Azure Function Triggers
| Trigger Type | Name | Description |
|---|---|---|
| Queue | ProcessFindQueue | Processes email find requests from queue |
| Queue | ProcessSearchQueue | Processes email search requests |
| HTTP | Various (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.
| Method | Description |
|---|---|
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.
| Method | Description |
|---|---|
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.
| Method | Description |
|---|---|
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 Name | Purpose |
|---|---|
email-find-queue | Primary email finding requests |
email-search-queue | Search/lookup requests |
Storage: Configured via FunctionsStorage:ConnectionString in appsettings.json.
Environment Detection
Functions use AZURE_FUNCTIONS_ENVIRONMENT to load environment-specific config:
Development→appsettings.Development.jsonStaging→appsettings.Staging.jsonProduction→appsettings.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.cs→SetupServices.Init()EmailFinderServices/Setup/SetupRepositories.cs→SetupRepositories.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)
| Source | Data | Mechanism |
|---|---|---|
| sopromasterdata | Find requests (prospect name + company) | Azure Queue |
| Manual/WebAPI | Single or batch find requests | HTTP endpoint |
Downstream (results go to)
| Target | Data | Mechanism |
|---|---|---|
| sopromasterdata | Found email + verification status | Callback / DB update |
| Azure Blob Storage | Raw provider JSON responses | Blob write after each provider call |
Cross-Feature Dependencies
| Feature | Relationship |
|---|---|
| Campaign Management | Campaigns trigger email finding for their prospects |
| Audience Management | Audience prospects need email addresses |
| Verification Pipeline | Found emails may be re-verified later |
| Email Sending | Found + verified emails enable campaign delivery |