Skip to content

Fold provider alias domains to a canonical form (googlemail.com, me.com, mac.com) - #26

Merged
gmr merged 2 commits into
gmr:mainfrom
jogunox:canonical-domain-folding
Jul 29, 2026
Merged

gmr merged 2 commits into
gmr:mainfrom
jogunox:canonical-domain-folding

Conversation

@jogunox

@jogunox jogunox commented Jul 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Folds provider alias domains to a single canonical form during normalization, so that addresses which reach the same mailbox normalize to the same value:

  • Google: googlemail.com → gmail.com
  • Apple: me.com, mac.com → icloud.com

Fixes #25.

Approach

  • New per-provider CanonicalDomains mapping (Mapping[str, str], alias → canonical) on MailboxProvider, defaulting to an empty, immutable MappingProxyType. Populated for Apple and Google only.
  • Normalizer.normalize applies the fold after the existing local-part rules:
    domain_part = provider.CanonicalDomains.get(domain_part, domain_part)
  • Only a provider's own consumer alias domains are listed. Custom domains that merely share MX servers are never folded — the same principle as the StripPeriodDomains guard added in Period stripping incorrectly applied to Google Workspace domains (only consumer Gmail should strip dots) #23 for Google Workspace.
  • Domains that share a provider but are separate mailboxes (Microsoft outlook.com/hotmail.com, Yahoo yahoo.com/aol.com) are intentionally left unchanged, with tests locking that in.

Tests

  • MX-path unit tests for Google + Apple folding, canonical-domain-unchanged, period preservation while folding (Apple has no STRIP_PERIODS), and a negative test (hotmail.com not folded).
  • skip_dns static-map tests for the same cases.
  • Live-DNS e2e tests (matching the existing NormalizerTestCase pattern) confirming gmail.com/googlemail.com collapse to the same address.
  • Equivalence tests asserting aliases collapse and distinct Microsoft domains do not.

All 70 tests pass; pre-commit (ruff format + ruff) clean; coverage 100% on providers.py. README normalization-rules table updated with a Domain Folding column.

Summary by CodeRabbit

  • New Features
    • Added domain folding to canonicalize recognized provider alias domains during email normalization.
    • googlemail.com now normalizes to gmail.com.
    • me.com and mac.com now normalize to icloud.com.
    • Keeps distinct cross-provider domains (e.g., hotmail.com vs outlook.com) from collapsing.
  • Documentation
    • Updated the README “Normalization Rules” to document the new Domain Folding behavior and canonicalization notes.
  • Tests
    • Expanded coverage for alias folding, canonical equivalence, and end-to-end async normalization.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7dcf105f-a68c-447c-a727-f3be76858345

📥 Commits

Reviewing files that changed from the base of the PR and between 98bb587 and 98e973f.

📒 Files selected for processing (5)
  • README.md
  • email_normalize/__init__.py
  • email_normalize/providers.py
  • tests/test_normalize.py
  • tests/test_normalizer.py
✅ Files skipped from review due to trivial changes (1)
  • README.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/test_normalizer.py
  • email_normalize/init.py
  • email_normalize/providers.py
  • tests/test_normalize.py

📝 Walkthrough

Walkthrough

Provider-specific alias domains are folded to canonical domains during normalization. Google maps googlemail.com to gmail.com, while Apple maps me.com and mac.com to icloud.com. Tests and README documentation cover positive and negative cases.

Changes

Provider Domain Folding

Layer / File(s) Summary
Provider canonical-domain contract
email_normalize/providers.py, README.md
Providers expose explicit canonical-domain mappings; Apple and Google define supported aliases, and the README documents folding rules and exclusions.
Canonical-domain application
email_normalize/__init__.py
Normalizer.normalize applies the provider’s canonical-domain mapping after local-part normalization, preserving unmapped domains.
Folding behavior validation
tests/test_normalize.py, tests/test_normalizer.py
Tests cover Google and Apple folding, skip-DNS normalization, canonical equivalence, provider results, and distinct Microsoft domains.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Normalizer
  participant MailboxProvider
  Client->>Normalizer: normalize email address
  Normalizer->>MailboxProvider: resolve provider and canonical domain
  MailboxProvider-->>Normalizer: canonical domain mapping
  Normalizer-->>Client: normalized address and provider
Loading

Poem

I’m a rabbit with aliases tucked neat,
Folding domains to make forms meet.
Google hops to Gmail’s door,
Apple lands on iCloud’s shore.
Hotmail stays distinct in its seat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.31% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the core change: folding provider alias domains to canonical forms.
Linked Issues check ✅ Passed The PR implements explicit alias-domain folding for Google and Apple, preserves distinct mailbox domains, and adds the requested tests and docs.
Out of Scope Changes check ✅ Passed The changes stay focused on canonical domain folding, related tests, and README updates with no obvious unrelated additions.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_normalize.py (1)

153-163: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

test_google_gmail_canonical_unchanged duplicates existing test_google_consumer_gmail.

Lines 124–134 (test_google_consumer_gmail) and lines 153–163 (test_google_gmail_canonical_unchanged) are functionally identical — same UUID-with-periods local part, same gmail.com domain, same MX records, same expected output. Only the docstrings differ. Consider removing the duplicate or differentiating the assertion (e.g., testing a non-period local part to specifically isolate the "no folding" behavior).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_normalize.py` around lines 153 - 163, The
test_google_gmail_canonical_unchanged case duplicates
test_google_consumer_gmail. Remove the duplicate test, or change its input and
expected assertion to uniquely verify that canonical gmail.com addresses are not
folded, while preserving the existing Gmail normalization coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_normalize.py`:
- Around line 153-163: The test_google_gmail_canonical_unchanged case duplicates
test_google_consumer_gmail. Remove the duplicate test, or change its input and
expected assertion to uniquely verify that canonical gmail.com addresses are not
folded, while preserving the existing Gmail normalization coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4130e9b7-9473-42a2-85ec-bcfbb021d091

📥 Commits

Reviewing files that changed from the base of the PR and between b36e592 and 287a6ab.

📒 Files selected for processing (5)
  • README.md
  • email_normalize/__init__.py
  • email_normalize/providers.py
  • tests/test_normalize.py
  • tests/test_normalizer.py

@jogunox

jogunox commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the CodeRabbit nitpick in 98bb587: test_google_gmail_canonical_unchanged now uses a plain local part (no periods, no plus) so it isolates the one behavior it claims to test — that gmail.com is the canonical domain and is never folded away. Previously the period-laden local part made dot-stripping mask the domain check, leaving it functionally identical to test_google_consumer_gmail. Confirmed it's meaningful via mutation testing (injecting a gmail.com fold makes it fail). Full suite still 70/70 green, pre-commit clean.

jogunox added 2 commits July 11, 2026 21:54
googlemail.com now folds to gmail.com, and me.com/mac.com fold to
icloud.com, so addresses that reach the same mailbox normalize to the
same value. Aliasing is opt-in per provider via a new CanonicalDomains
mapping, applied only to a provider's own consumer alias domains and
never to custom domains that merely share MX servers. Domains that share
a provider but are separate mailboxes (Microsoft outlook/hotmail, Yahoo
yahoo/aol) are intentionally left unchanged.
test_google_gmail_canonical_unchanged used a period-laden local part,
making it functionally identical to test_google_consumer_gmail — dot
stripping masked whether the domain was actually folded. Use a plain
local part (no periods, no plus) so the test verifies exactly one
thing: gmail.com is the canonical Google domain and is never folded
away. Verified via mutation (injecting a gmail.com fold now fails it).
@jogunox
jogunox force-pushed the canonical-domain-folding branch from 98bb587 to 98e973f Compare July 12, 2026 04:54
@gmr
gmr merged commit a0181de into gmr:main Jul 29, 2026
5 checks passed
gmr added a commit that referenced this pull request Jul 29, 2026
- Fold provider alias domains to a canonical form (#25, #26):
  googlemail.com -> gmail.com, me.com/mac.com -> icloud.com. Domains
  that share a provider but are separate mailboxes (outlook.com/
  hotmail.com, yahoo.com/aol.com) are intentionally left unchanged.
- Update dependencies: pymdown-extensions (#27)

Note: this changes normalized output for googlemail.com, me.com, and
mac.com addresses, so stored normalized values may need recomputing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fold provider alias domains to a canonical form (googlemail.com -> gmail.com, me.com/mac.com -> icloud.com)

2 participants