parse-email-address
Version:
Parse/validate email addresses with RFC-5321, and message header address lists with RFC-5322.
125 lines (124 loc) • 4.18 kB
JavaScript
import { asciiSafeLowerCase } from './ascii-safe-lower-case.js';
import { canonicalize, parse } from './smtp-address-parser.js';
/**
* Parse a single RFC 5321 email address into parts. This is the strict, envelope-level grammar: it
* accepts nothing but a bare `user@domain`. To read an address out of an RFC 5322 message header
* (which may carry display names, comments, groups, and multiple addresses), use
* `parseEmailAddressList` or `parseHeaderEmailAddress` instead.
*
* This uses `parse` from [`smtp-address-parser`
* v1.1.0](https://www.npmjs.com/package/smtp-address-parser/v/1.1.0).
*
* @example
*
* ```ts
* import {parseEmailAddress} from 'parse-email-address';
*
* const result1 = parseEmailAddress('simple@example.org');
* // result1 is `{user: 'simple', domain: 'example.org', full: 'simple@example.org'}`
*
* const result2 = parseEmailAddress('tld-too-short@foo.x');
* // result2 is `undefined`
*
* const result3 = parseEmailAddress('Simple Person <simple@example.org>');
* // result3 is `undefined`
* ```
*
* @returns `undefined` if the given email address is invalid.
* @throws Nothing, this will never throw an error.
*/
export function parseEmailAddress(emailAddress) {
try {
if (!emailAddress) {
return undefined;
}
const parsed = parse(emailAddress);
return {
user: parsed.localPart.DotString ?? parsed.localPart.QuotedString,
domain: parsed.domainPart.AddressLiteral ?? parsed.domainPart.DomainName,
full: emailAddress,
};
}
catch {
return undefined;
}
}
/**
* Normalizes an email address for string comparisons. It is discouraged to use the output of this
* for sending email as even the weird parts of a valid email address may be required for the user's
* specific email server to properly handle emails.
*
* This uses `canonicalize` from [`smtp-address-parser`
* v1.1.0](https://www.npmjs.com/package/smtp-address-parser/v/1.1.0) and lowercases the entire
* string. A character is never lowercased across scripts into ASCII, so an address containing
* U+212A KELVIN SIGN does not normalize to the same string as one containing an ASCII `k`.
*
* A quoted local part may itself contain an `@`, so the output is not safe to split on `@`. Use
* {@link parseEmailAddress} when you need the domain.
*
* @example
*
* ```ts
* import {normalizeEmailAddress} from 'parse-email-address';
*
* const result1 = normalizeEmailAddress('SIMPLE@EXAMPLE.ORG');
* // result1 is `'simple@example.org'`
*
* const result2 = normalizeEmailAddress('tld-too-short@foo.x');
* // result2 is `undefined`
*
* const result3 = normalizeEmailAddress('"a@b"@example.org');
* // result3 is `'"a@b"@example.org'`, which contains two `@`
* ```
*
* @returns `undefined` if the given email address is invalid.
* @throws Nothing, this will never throw an error.
*/
export function normalizeEmailAddress(emailAddress) {
try {
if (!emailAddress) {
return undefined;
}
return asciiSafeLowerCase(canonicalize(emailAddress));
}
catch {
return undefined;
}
}
/**
* Checks if the given email address is a valid RFC 5321 email address. As with
* {@link parseEmailAddress}, this rejects everything but a bare `user@domain`, so header forms like
* `Simple Person <simple@example.org>` are _not_ valid here.
*
* This uses `parse` from [`smtp-address-parser`
* v1.1.0](https://www.npmjs.com/package/smtp-address-parser/v/1.1.0).
*
* @example
*
* ```ts
* import {isValidEmailAddress} from 'parse-email-address';
*
* const result1 = isValidEmailAddress('simple@example.org');
* // result1 is `true`
*
* const result2 = isValidEmailAddress('SIMPLE@EXAMPLE.ORG');
* // result2 is `true`
*
* const result3 = isValidEmailAddress('tld-too-short@foo.x');
* // result3 is `false`
* ```
*
* @throws Nothing, this will never throw an error.
*/
export function isValidEmailAddress(emailAddress) {
try {
if (!emailAddress) {
return false;
}
parse(emailAddress);
return true;
}
catch {
return false;
}
}