Skip to content
fumbledlolPublic

About

Normalize email addresses across Gmail, Outlook, Yahoo, and Fastmail to stop duplicate signups

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

emailnorm

Go Reference License: MIT

Go library for canonicalizing email addresses to prevent duplicate accounts and registration spam.

Why normalization matters

Most web services store email addresses as raw, lowercased strings. Spammers exploit provider-specific routing quirks to register multiple accounts that route into one mailbox:

To a standard database query, these look like distinct users. To Google, every one of these delivers to [email protected].

Naive normalizers often cause serious deliverability bugs by over-stripping:

  • Stripping dots on Google Workspace or Fastmail can collide separate coworkers.
  • Stripping plus signs on Yahoo, Tuta, GMX, Web.de, Naver, QQ Mail, or Brave aliases breaks deliverability because those services reject sub-addressing (550 User not found).
  • Merging Hotmail and Outlook causes collisions because Microsoft allows different people to own the same username across different domains.

emailnorm encodes verified routing rules for major email providers without collapsing distinct mailboxes.

Recommended storage pattern

When using emailnorm for user accounts, store both the raw email and the normalized email in separate database columns:

sql CREATE TABLE users ( id UUID PRIMARY KEY, email TEXT NOT NULL, -- Raw email as entered (e.g., [email protected]) normalized_email TEXT NOT NULL UNIQUE -- Canonical email (e.g., [email protected]) );

Why store both?

  • Outbound delivery: Send all transactional and marketing emails to the raw address. Users often configure mail filters based on their aliases (such as +news or +invoices) and expect mail to arrive at the address they entered.
  • User preference: Preserves the user's preferred casing and domain alias in the interface.
  • Deduplication and security: Use ormalized_email for unique constraints and login lookup queries. This prevents malicious or accidental duplicate registrations, multiple trial abuse, and referral fraud.

Supported providers

  • Google (gmail.com, googlemail.com): maps googlemail.com to gmail.com, strips dots, and removes +tag suffixes. Custom domains on Google Workspace preserve dots.
  • Proton (proton.me, protonmail.com, protonmail.ch, pm.me): maps alias domains to proton.me, strips plus tags, and preserves dots.
  • Fastmail (over 100 domains): folds subdomain addressing ([email protected] to [email protected]).
  • Apple iCloud (icloud.com, me.com, mac.com): maps me.com and mac.com to icloud.com, and strips plus tags.
  • Yandex (yandex.ru, ya.ru, and country TLDs): maps regional domains to yandex.ru, strips plus tags, and converts hyphens to dots (first-last to first.last).
  • Microsoft (outlook.com, hotmail.com, live.com, msn.com): strips plus tags while keeping separate domains distinct.
  • Mail.ru (mail.ru, bk.ru, inbox.ru, list.ru, internet.ru): strips plus tags while keeping separate domains distinct.
  • Zoho Mail and DuckDuckGo: strips plus tags and preserves dots.
  • Yahoo, Tuta, GMX, Web.de, Naver, Daum, QQ, NetEase, and Brave: keeps literal addresses without plus stripping so outgoing mail does not bounce.
  • Internationalized domains: normalizes Unicode to NFC and converts non-ASCII domain names to Punycode.

Installation

go get github.com/fumbledlol/emailnorm

Usage

Normalizing email addresses

package main

import (
	"fmt"

	"github.com/fumbledlol/emailnorm"
)

func main() {
	// Gmail: removes dots and plus tags, unifies googlemail
	fmt.Println(emailnorm.Normalize("  [email protected] "))
	// Output: [email protected]

	// Proton: maps alias domains to proton.me, removes plus tag
	fmt.Println(emailnorm.Normalize("[email protected]"))
	// Output: [email protected]

	// Yandex: maps regional domain, unifies hyphens and dots
	fmt.Println(emailnorm.Normalize("[email protected]"))
	// Output: [email protected]

	// Fastmail: folds subdomain addressing
	fmt.Println(emailnorm.Normalize("[email protected]"))
	// Output: [email protected]

	// GMX, Naver, Brave: keeps plus signs to prevent delivery failure
	fmt.Println(emailnorm.Normalize("[email protected]"))
	// Output: [email protected]

	// Internationalized domain names: converts to ASCII Punycode
	fmt.Println(emailnorm.Normalize("contact@München.de"))
	// Output: [email protected]
}

Inspecting provider rules

provider := emailnorm.DetectProvider("[email protected]")
fmt.Println(provider)                           // GMX
fmt.Println(provider.SupportsPlusAddressing())   // false
fmt.Println(provider.StripsDots())               // false

gmail := emailnorm.DetectProvider("[email protected]")
fmt.Println(gmail.StripsDots())                  // true

Normalization rules

Provider family Strip dots Strip plus tag Domain folding Example input Normalized output
Gmail Yes Yes googlemail.com -> gmail.com [email protected] [email protected]
Proton No Yes protonmail.*, pm.me -> proton.me [email protected] [email protected]
Fastmail No Yes Subdomain fold (*@user.<dom> -> user@<dom>) [email protected] [email protected]
iCloud No Yes me.com, mac.com -> icloud.com [email protected] [email protected]
Yandex No (- -> .) Yes ya.ru, yandex.* -> yandex.ru [email protected] [email protected]
Outlook / Hotmail No Yes Distinct domains [email protected] [email protected]
Mail.ru No Yes Distinct domains [email protected] [email protected]
Zoho Mail No Yes Distinct domains [email protected] [email protected]
DuckDuckGo No Yes Distinct domains [email protected] [email protected]
Brave aliases No No Literal routing [email protected] [email protected]
Yahoo No No Literal routing [email protected] [email protected]
Tuta No No Literal routing [email protected] [email protected]
GMX / Web.de No No Literal routing [email protected] [email protected]
Naver / Daum No No Literal routing [email protected] [email protected]
QQ / NetEase No No Literal routing [email protected] [email protected]
Custom / Generic No Yes Literal domain [email protected] [email protected]

Benchmarks

BenchmarkNormalize_Gmail-12       2113540    565.2 ns/op    112 B/op    4 allocs/op
BenchmarkNormalize_Proton-12      3206744    380.1 ns/op     56 B/op    2 allocs/op
BenchmarkNormalize_Fastmail-12    2263084    540.5 ns/op     72 B/op    3 allocs/op
BenchmarkNormalize_Yandex-12      3018289    407.6 ns/op     72 B/op    3 allocs/op

License

MIT

About

Normalize email addresses across Gmail, Outlook, Yahoo, and Fastmail to stop duplicate signups

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages