AbsoluteJS

Enrich

@absolutejs/enrichv0.1.4betaCommerce & Growth

Email verification, decision-maker email finding, and keyless profile enrichment without per-lookup API fees.

In-house B2B email verification and discovery — the engine commercial enrichment APIs (PDL, Apollo, Hunter, Clearbit) charge per lookup. You bring a name and a company domain; findEmail generates the corporate patterns and verifyEmail runs the full local pipeline from syntax and MX checks to an opt-in SMTP probe. A browser-safe /profile subpath adds keyless public-profile enrichment: avatars, company logos, and social-handle extraction with no per-lookup API.

#Installation

BASH
bun add @absolutejs/enrich

#Capabilities

Overview

In-house B2B email verification and discovery — the engine commercial enrichment APIs (PDL, Apollo, Hunter, Clearbit) charge per lookup. You bring the inputs (a name + a company domain); this resolves and verifies the email.

Licensed under BSL 1.1 (converts to Apache 2.0 on 2030-06-06). Use it to build your own products; you may not host it as a competing enrichment SaaS. See LICENSE.

What it does

findEmail({ firstName, lastName | fullName, domain }, { verifier?, knownPattern? })

— generates the corporate patterns (first.last, flast, …), then:

a knownPattern (one you've already learned for this domain) is applied

Show 7 more

directly — no probing,

with a verifier it confirms candidates best-first and returns the one

that's deliverable,

with neither it returns the top pattern at MX-only confidence.

The result's template (e.g. "first.last") is the learnable unit — store it per domain and pass it back as knownPattern to skip probing for everyone else there.

verifyEmail(email) — the full local pipeline: syntax → disposable/free/role

→ MX → (optional, opt-in) catch-all + SMTP probe → 0–100 confidence + status.

The verifier is pluggable — and that's the point

The "confirm" step is an interface, not a baked-in SMTP probe:

Bring a thin wrapper over a specialist (ZeroBounce, NeverBounce, Hunter's verifier, or your ESP's validation). Why not just probe SMTP ourselves? Because RCPT TO probing is mechanically a directory-harvest attack — mail servers detect it and blacklist the probing IP, which then tanks your own sending reputation. The specialists run it from warmed, rotated IP pools built to absorb that. Let them carry the risk for pennies a check; keep your domains clean.

Confidence scale

score — meaning

95 — SMTP-confirmed on a non-catch-all domain

60 — catch-all domain — the mailbox can't be individually confirmed

Show 2 more

45 — MX exists, SMTP inconclusive (port 25 blocked, greylisted, or skipSmtp)

0 — invalid syntax / no MX / SMTP-rejected / disposable

The built-in SMTP verifier (smtpVerifier) is opt-in — and carries warnings

The package ships smtpVerifier() so you can self-host the confirm step, but it's deliberately not the default:

It needs outbound port 25, which AWS/GCP/DigitalOcean block by default.

Even with egress, probing risks blacklisting your IP (see above) and the

Show 2 more

biggest mail hosts (Gmail, Microsoft) return ambiguous answers to defeat harvesters — so its accuracy is degraded where it matters most.

Only reach for it from a host/relay you've dedicated to verification and whose reputation you're willing to spend. For everyone else: findEmail discovers the pattern (free, zero abuse signature), a specialist verifier confirms it, and you store the confirmed template per domain — over time that learned dataset, built from real outcomes rather than probing, is the moat the paid providers actually have.

Public-profile enrichment (@absolutejs/enrich/profile)

Keyless avatar/logo derivation from identifiers you already have — no per-lookup API. Browser-safe subpath (no node: imports), so the same module runs in your backend and your frontend bundle:

personAvatarCandidates({ imageUrl?, email?, twitterUrl?, instagramUrl?, githubUrl? })

— every avatar URL derivable from the person's identifiers, best-first: a photo you sourced yourself, then email (Gravatar et al. via unavatar.io), then X / Instagram / GitHub handles. Use it to offer a choice of avatars.

Show 10 more

personAvatarUrl(person) — the first (most trusted) candidate, or null.

unavatar URLs carry fallback=false, so they 404 when nothing is found and an can drop to initials. Loading from the client keeps the identifier off your server's egress.

validatedAvatarUrl(person, timeoutMs?) — server-side: the first candidate

that HEAD-validates as a real image, for when you persist the result.

validateImageUrl(url, timeoutMs?) — HEAD-check any image URL.

companyLogoUrl(website, sizePx?) — company logo via Google's keyless

favicon service (Clearbit's logo API is sunset; DuckDuckGo has gaps).

socialUrlsFromLinks(links) — sort a loose { url, platform? }[] link

list (an LLM's "notable links", a scraped profile) into canonical per-platform URL fields, matching the declared platform first and the URL host second.

socialHandle(url, hosts) — extract a clean handle from a profile URL.

Email discovery

findEmail generates corporate patterns (first.last, flast, …), applies a knownPattern directly when you have one, and confirms candidates best-first through an optional verifier.

Local verification pipeline

verifyEmail runs syntax, disposable/free/role, and MX checks, plus an opt-in catch-all and SMTP probe, returning a 0-100 confidence and status.

Pluggable verifier

The confirm step is an EmailVerifier interface — bring a thin wrapper over ZeroBounce, NeverBounce, Hunter, or your ESP so specialists carry the SMTP-probing blacklist risk.

Learnable pattern templates

Every result carries a template (for example "first.last") — store it per domain and pass it back as knownPattern to skip probing for everyone else there.

Keyless profile enrichment

personAvatarCandidates, personAvatarUrl, and companyLogoUrl derive avatars and logos from identifiers you already have, keylessly, from a browser-safe subpath.

Social link normalization

socialUrlsFromLinks and socialHandle sort loose link lists into canonical per-platform URL fields and extract clean handles.

Outcomes

What you can build

Overview

In-house B2B email verification and discovery — the engine commercial enrichment APIs (PDL, Apollo, Hunter, Clearbit) charge per lookup. You bring the inputs (a name + a company domain); this resolves and verifies the email.

What it does

findEmail({ firstName, lastName | fullName, domain }, { verifier?, knownPattern? })

The verifier is pluggable — and that's the point

The "confirm" step is an interface, not a baked-in SMTP probe:

Hardening checklist

Production guidance

Make every external boundary explicitPin the deployed @absolutejs/enrich version, replace example or memory-backed dependencies with durable implementations, bound external calls, protect credentials, and emit enough evidence to retry or recover safely.

Follow in order

Troubleshooting path

1
Trace from the first failed boundary
Reproduce the smallest canonical @absolutejs/enrich example, confirm the supported entry point and version in the API explorer, then inspect the first boundary that did not produce its documented result.

#What it does

Partial snippet

findEmail({ firstName, lastName | fullName, domain }, { verifier?, knownPattern? })

TS
import { findEmail } from "@absolutejs/enrich";

// Discovery-only — no SMTP, no third-party call:
await findEmail({ fullName: "Jane Doe", domain: "acme.com" });
// → { email: "jane.doe@acme.com", status: "unknown", confidence: 45, template: "first.last" }

// With a verifier you bring (ZeroBounce / Hunter / your ESP):
await findEmail({ fullName: "Jane Doe", domain: "acme.com" }, { verifier });
// → { email: "jane.doe@acme.com", status: "deliverable", confidence: 95, template: "first.last" }

#The verifier is pluggable — and that's the point

Partial snippet

The "confirm" step is an interface, not a baked-in SMTP probe:

TS
type EmailVerifier = (email: string) => Promise<{ status; confidence; catchAll? }>;

#Quick Start

Partial snippet

Pattern generation is free and carries zero abuse signature; the pluggable verifier upgrades a candidate to SMTP-confirmed confidence.

TS
import { findEmail } from '@absolutejs/enrich';

// Discovery-only — no SMTP, no third-party call:
await findEmail({ domain: 'acme.com', fullName: 'Jane Doe' });
// → { email: 'jane.doe@acme.com', status: 'unknown',
//     confidence: 45, template: 'first.last' }

// With a verifier you bring (ZeroBounce / Hunter / your ESP):
await findEmail(
	{ domain: 'acme.com', fullName: 'Jane Doe' },
	{ verifier }
);
// → { email: 'jane.doe@acme.com', status: 'deliverable',
//     confidence: 95, template: 'first.last' }

#Keyless profile enrichment

Partial snippet

The /profile subpath has no node: imports, so the same module runs in your backend and your frontend bundle.

TS
import {
	companyLogoUrl,
	personAvatarUrl
} from '@absolutejs/enrich/profile';

const avatar = personAvatarUrl({
	email: 'jane.doe@acme.com',
	githubUrl: 'https://github.com/janedoe'
});
// First (most trusted) derivable avatar URL, or null.

const logo = companyLogoUrl('https://acme.com', 128);
// Company logo via Google's keyless favicon service.
SMTP probing is opt-in
The built-in smtpVerifier is deliberately not the default: it needs outbound port 25 (blocked by AWS/GCP/DigitalOcean), risks blacklisting your IP, and the biggest mail hosts return ambiguous answers to defeat harvesters. Only use it from a host whose reputation you are willing to spend.
Discover, confirm, learn
The intended loop: findEmail discovers the pattern for free, a specialist verifier confirms it, and you store the confirmed template per domain — that learned dataset is the moat the paid providers actually have.

#API reference

Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.

41 symbols
bimiLogoUrlexportPermalink
TS
bimiLogoUrl
Exported from @absolutejs/enrich
Use this API in an outcome:Build commerce growth

Continue toward an outcome

These playbooks show where this package fits, how to verify the combined system, and what changes before production.

Current package surface

What ships today

@absolutejs/enrichv0.1.4 · betaCommerce & GrowthnpmSource
4entry points55symbols

Import surface · click to copy