blog
Email Local-Part Case Sensitivity: RFC Rules vs Provider Behavior
Learn where local-part case sensitivity appears in email standards, why providers usually ignore case, and how to test reliable identity matching.

An email address can be case-sensitive in one place and effectively case-insensitive in another. That sounds like a riddle designed by a committee, but it becomes manageable once you separate delivery from account identity.
The short answer is:
- the domain after
@is case-insensitive; - SMTP requires senders to preserve the case of the local part before
@; - most large mailbox providers treat local-part case variants as the same inbox; and
- your application still needs an explicit rule for signup, login, password reset, and duplicate detection.
For the everyday Gmail and Outlook answer, read Are emails case sensitive?. This guide stays with the protocol rule and the engineering decisions it creates.
What the email standards actually say
Take Ada.Lovelace@example.com:
| Address part | Example | Matching rule |
|---|---|---|
| Local part | Ada.Lovelace |
The receiving domain defines its meaning; SMTP requires case to be preserved |
| Domain | example.com |
Case-insensitive under normal DNS rules |
RFC 5321 section 2.4 says the local part must be treated as case-sensitive during SMTP handling. In the same breath, it discourages mailbox providers from exploiting that distinction because doing so hurts interoperability. The standard is strict about transport and pragmatic about mailbox design.
There is another important boundary in RFC 5321 section 2.3.11: only the host named by the domain may assign meaning to the local part. A sender cannot safely decide that Ada.Lovelace, ada.lovelace, and adalovelace are one mailbox. That decision belongs to example.com.
So SMTP software should preserve:
Ada.Lovelace@example.com
rather than silently rewriting it to:
ada.lovelace@example.com
The rewritten address will work at many providers, but "usually works" is not the same contract as "always equivalent."
Why provider behavior looks different
Most consumer and business mailbox systems deliberately avoid case-distinct mailboxes. A person who types Jane@example.com instead of jane@example.com expects the same inbox, not a surprise twin living next door.
That practical behavior is why applications commonly use a lowercase email key for account lookup. It is a reasonable product policy when you control the account system and have tested the mailbox providers you support. It is not a universal SMTP normalization rule.
Keep these questions separate:
- Where should this message be delivered? Preserve the address supplied or verified by the mailbox owner.
- Which application account does this input identify? Apply the matching rule your product has chosen.
- What should the interface display? Usually keep the person's verified or preferred spelling.
One string can answer all three questions in a simple system. Keeping separate values makes migrations, support, and edge cases much less mysterious.
A safer storage model
A practical account record can keep:
| Field | Purpose | Example |
|---|---|---|
| Delivery address | Exact verified destination used when sending | Ada.Lovelace@example.com |
| Identity key | Value used for login and uniqueness under your policy | ada.lovelace@example.com |
| Display address | Optional spelling shown back to the person | Ada.Lovelace@example.com |
Do not create three columns merely for decoration. The useful distinction is between the address you deliver to and the key you compare. The display value can be the verified delivery address when that is enough.
Here is a small TypeScript example. It is an identity-key helper, not a full email syntax validator:
type LocalPartPolicy = 'preserve' | 'fold-ascii-case'
export function buildEmailKeys(
input: string,
localPartPolicy: LocalPartPolicy = 'preserve',
) {
const address = input.trim()
const at = address.lastIndexOf('@')
if (at <= 0 || at === address.length - 1) {
throw new Error('Enter a complete email address')
}
const localPart = address.slice(0, at)
const domain = address.slice(at + 1).toLowerCase()
if (
localPartPolicy === 'fold-ascii-case' &&
/[^\x00-\x7F]/.test(localPart)
) {
throw new Error('Use a separate SMTPUTF8 identity policy')
}
const identityLocalPart =
localPartPolicy === 'fold-ascii-case'
? localPart.toLowerCase()
: localPart
return {
deliveryAddress: `${localPart}@${domain}`,
identityKey: `${identityLocalPart}@${domain}`,
}
}
Use preserve for arbitrary delivery addresses and systems that must follow SMTP semantics. Use a case-folding account policy only when your application intentionally treats ASCII case variants as one identity. Validate the complete address with a maintained library, and verify ownership before trusting it as an account identifier.
Choose the policy by job
There is no single correct comparison rule for every email-shaped value.
| Job | Sensible default |
|---|---|
| Deliver to an external mailbox | Preserve the local part; lowercase or otherwise canonicalize the domain using a standards-aware library |
| Match logins in a consumer application | Use one documented case-insensitive identity key, while retaining the verified delivery address |
| Create mailboxes on a domain you operate | Decide whether local parts are case-sensitive, then make provisioning, login, aliases, and support follow the same rule |
| Store a MailSlurp-generated inbox address | Keep the generated address exactly as returned |
| Compare security allowlists or suppression entries | Use the same versioned comparison rule as the system that created the entry; do not improvise at the point of use |
The last row deserves care. RFC 6943 describes email-like values as identifiers whose comparison can be uncertain. A false match in a security decision can be worse than a failed newsletter send. Normalize once under a known policy and reuse that result everywhere the identity is compared.
Do not copy Gmail's other address rules
Case folding, dot removal, and plus addressing are separate behaviors.
Do not globally turn:
ada.lovelace+receipts@example.com
into:
adalovelace@example.com
Some providers ignore dots for particular consumer domains. Some use +tag as a routing hint. Other providers treat those characters as part of a distinct mailbox. Only apply provider-specific transformations when you own the domain or have a tested contract with that provider.
This is especially important for aliases, catch-all domains, inbound routing, and generated test addresses. Helpful-looking cleanup can quietly send a password reset to the wrong place.
Internationalized addresses need their own path
SMTPUTF8 in RFC 6531 permits non-ASCII characters in mailbox addresses. It does not grant applications permission to lowercase or Unicode-normalize every local part.
If you accept internationalized email addresses:
- use a library that understands SMTPUTF8 and internationalized domains;
- preserve the verified local part for delivery;
- avoid locale-dependent case conversion;
- test visually confusable characters and account-recovery flows; and
- record which normalization policy produced each identity key.
A simple toLowerCase() example is not a complete international email policy. Treat it as an ASCII account convention, not a protocol parser.
Migrate an existing user table without lockouts
Changing comparison rules can merge records that were previously distinct. Before adding a case-insensitive unique index:
- Build the proposed identity key beside the current value.
- List collisions such as
Pat@example.comandpat@example.com. - Resolve each collision using verified ownership and account history, not spelling alone.
- Keep the confirmed delivery address on the surviving account.
- Update login, signup, password reset, SSO, billing, CRM, webhooks, and suppression handling together.
- Reject a second signup whose identity key already exists.
- Test old sessions, reset links, and audit records before enforcing the new unique key.
Do not silently merge two accounts during a backfill. The database may be pleased with its tidiness while two real people are very much not.
Test case handling with a real inbox
MailSlurp gives each test a private address and an inbox you can inspect through the API. Use the generated address exactly as returned, then test your application's identity behavior around it:
- Create a fresh inbox with the Email Address API.
- Register a test account using that exact delivery address.
- Attempt a second signup with only the ASCII letter case changed; your app should follow its documented duplicate-account rule.
- Request login, OTP, magic-link, and password-reset email using another case variant.
- Confirm the application looks up the same account but still sends to the stored delivery address.
- Wait for the message in Email Sandbox, then assert its recipient, subject, code or link, and expiry.
- Complete the user action and remove the test inbox during cleanup.
This catches the bug that mailbox-only testing misses: delivery can succeed while account lookup, token binding, or uniqueness fails.
A compact release checklist
Before shipping a case-policy change, confirm:
- the domain is compared case-insensitively;
- the local part is preserved for delivery;
- the account identity rule is written down and used by every auth path;
- collisions were reviewed before a unique key was added;
- dots and plus tags are not stripped as a global rule;
- internationalized addresses take a standards-aware path;
- generated inbox addresses remain unchanged; and
- signup, login, reset, OTP, magic-link, bounce, and suppression flows share the same policy.
MailSlurp's email integration testing and email webhooks help turn those checks into repeatable tests. If a message reaches the inbox but the link opens the wrong account, the test should fail where a person would feel the problem.
Common questions
Is the part before the at sign case-sensitive?
SMTP says its case must be preserved and allows the receiving host to distinguish case. Most modern providers choose not to create case-distinct mailboxes.
Should I lowercase every email address before sending?
No. Preserve the local part of an arbitrary recipient address. Lowercasing a domain is safe under normal DNS rules; lowercasing the local part is an application or provider policy, not a universal transport rule.
Can my app use lowercase email keys for login?
Yes, if that is an intentional account policy. Keep the verified delivery address, apply the same key in every authentication flow, detect migration collisions, and test the behavior.
Are dots and plus tags part of case normalization?
No. They are separate, provider-specific address behaviors. Do not remove them globally.
Should I change the case of a MailSlurp inbox address?
Use the generated MailSlurp address exactly as returned. Test your application's case-insensitive account lookup without rewriting the destination used for delivery.
Final take
The domain is case-insensitive. The local part belongs to the receiving domain and must survive SMTP transport unchanged. Your account system may still choose a case-insensitive identity key, but that is a deliberate product rule with migration and security consequences.
Keep the delivery address and comparison rule distinct, then test the whole journey with MailSlurp. One person should get one account, one reset link, and no case-related surprises.