Scoring — Email

mercury.score.score_email(link_emails: list[str], customer_emails: list[str]) -> float

Normalization

mercury.normalize.normalize_email lowercases and strips surrounding whitespace. No local-part canonicalization (no +tag stripping, no .-ignoring) — those belong in a later iteration.

Agreement rule

The score is 1.0 if any entry in link_emails normalizes to a value present in customer_emails; 0.0 otherwise. Exact match on the normalized string only — domain-only and local-part-only agreement are deliberately not credited in v1.

Candidate construction

The caller (mercury.match.evaluate) assembles customer_emails as the union of:

  • every user.email on the Mercury company record;
  • the company’s contactEmail.

This is what makes link 5 match: the link’s ram@example.fr doesn’t match the user’s ram@example.com, but it does match the company contactEmail. Treating every Mercury-known email as a candidate is essential.

Edge cases

  • Empty link emails → 0.0.
  • Empty candidates → 0.0 (defensive — shouldn’t happen in production).
  • TLD-only mismatch (e.g. ram@example.com vs ram@example.fr) is a full 0.0 — the TLD is significant.

Combiner contribution

Weight: EMAIL_WEIGHT = 1.5 (see scoring-combiner). An email match alone does not clear the 2.5 threshold.