Record Class EmailAddress
- Record Components:
localPart- the"tolkien"fromJ.R.R. Tolkien <tolkien@lotr.org>domain- the"lotr.org"fromJ.R.R. Tolkien <tolkien@lotr.org>. Note that for internationalized domain, this is the punycode in ASCII. You can useunicodeDomain()to access the non-encoded domain.hasI18nDomain()can be used to check if the domain is internationalized.displayName- the"J.R.R. Tolkien"fromJ.R.R. Tolkien <tolkien@lotr.org>. Note that this holds the raw transport-safe format (including any RFC 2047 encoded-words). You can useunicodeDisplayName()to access the decoded Unicode representation.
javax.mail.InternetAddress.
See README for a comprehensive architectural, security, and performance comparison against Jakarta Mail and JMail.
For example:
EmailAddress address = EmailAddress.of("J.R.R. Tolkien <tolkien@lotr.org>");
// address.displayName() => "J.R.R. Tolkien"
// address.localPart() => "tolkien"
// address.domain() => "lotr.org"
RFC 5322 Compliance Profile
- Address Specification (addr-spec): Supports the standard
local-part@domainformat (RFC 5322 §3.4.1). - Quoted Local-Parts: Fully supports double-quoted local-parts
(RFC 5322 §3.4.1), with backslash-escaped characters. In order to provide a clean,
canonical representation, enclosing quotes are automatically stripped and backslash
escapes are unescaped when stored in the
localPartproperty (e.g.,"john doe" -> "john doe"). While serializing viaaddress()ortoString(), appropriate quotes and escapes are dynamically and safely re-introduced if necessary to maintain syntactical validity under RFC 5322 (since v10.3). - Name-Addr: Fully supports
"display-name" <addr-spec>syntax (RFC 5322 §3.4). - Quoted-Strings: Complies with RFC 5322 §3.2.4, supporting backslash-escaped characters within double-quoted display names.
- Phrases (unquoted names): Supports RFC 5322 "atoms" in
display names, forbidding specials, i.e. the
<,>,;,\, and"characters, while allowing periods, commas, colons, brackets, and parentheses for real-world usability (e.g., "[JIRA] (PROJ-123)"). - Folding White Space (FWS): Supports optional whitespace between the display name and the angle-bracketed address.
- Address-List: Supports semicolon as separators; allows real-world variations like trailing commas, two-commas-in-a-row etc.
Strict Email Address Validation
Unlike legacy javax.mail.InternetAddress from Java/Jakarta Mail, this class is
backed by a strict email address parser and a validated domain model. This improves security,
preventing common email parsing exploits such as:
- Email Parsing Differentials: Inputs like
<legitimate@trusted.com>attacker@evil.comare strictly rejected instead of being silently truncated or partially parsed, preventing privilege escalation or routing bypasses. - Display Name Spoofing (RFC 2047): Display names are preserved literally
in their raw/encoded form by default (preventing visual spoofing/phishing side-channels).
Safe opt-in decoding is provided explicitly via
unicodeDisplayName(). - Group Addresses and Multi-@ Local-Parts: Group address syntaxes and unquoted multi-@ injections are strictly disallowed.
Comparison with javax.mail.InternetAddress (Java / Jakarta Mail)
| Feature/Security Aspect | InternetAddress |
EmailAddress |
|---|---|---|
| Immutability | Mutable POJO | Immutable record |
| DNS labels | Permissive (allows illegal hyphens) | Rejects invalid/misplaced hyphens |
| I18n | Often requires Encoded-Words | Native BMP support |
| Parsing Differential | Vulnerable (silently discards trailing parts like <a@b.com>c@d.com) |
Secure (strictly rejects trailing unconsumed text via parser exceptions) |
| Group Addresses | Permissive (parses RFC-822 group syntax implicitly) | Strictly rejected (enforces single address structure) |
| RFC 2047 Encoded Words | Automatic or permissive (decodes or accepts encoded words in display name, local-part, or domain, risking address spoofing and routing hijacking) | Defensively rejected in local-part and domain. Supported in display name via safe, explicit opt-in unicodeDisplayName() |
| Multi-@ Local-Parts | Inconsistent (allows unquoted @ in local-part) |
Strictly rejected (unquoted @ is forbidden) |
Intentionally Omitted Legacy Features
To maintain compatibility with modern MTAs (Gmail, Outlook) and mitigate header injection risks, the following RFC 5322 edge cases are excluded:
- Comments (CFWS): (e.g.,
name(comment) <addr>) - De facto obsolete. - Domain Literals: (e.g.,
user@[192.168.1.1]) - IP routing is rarely supported. - RFC 2047 Encoded Words in address fields: (e.g.,
=?UTF-8?Q?Admin?=@domain.com) - Strictly rejected to prevent downstream mailer decoding exploits.
- Since:
- 9.9.4
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final Parser<EmailAddress> The parser for email address, according to RFC 5322, and supporting BMP characters. -
Constructor Summary
ConstructorsConstructorDescriptionEmailAddress(String localPart, String domain, Optional<String> displayName) Prefer using theof(java.lang.String, java.lang.String)factory method. -
Method Summary
Modifier and TypeMethodDescriptionaddress()Returns theaddr-spec, in the form ofuser@mycompany.com.alias()Returns the "alias" (or "detail") part of the local-part after the first+separator, according to RFC 5233 subaddressing.Returns the value of thedisplayNamerecord component.domain()Returns the value of thedomainrecord component.final booleanIndicates whether some other object is "equal to" this one.final inthashCode()Returns a hash code value for this object.booleanReturns true if this address has an internationalized domain, in which casedomain()will be puny-coded.Returns the value of thelocalPartrecord component.static EmailAddressParsesaddressand throwsParser.ParseExceptionif failed.static EmailAddressFor example:EmailAddress.of("user", "mycompany.com").static EmailAddressDeprecated.static List<EmailAddress> parseAddressList(String addressList) ParsesaddressListaccording to RFC 5322 and returns an immutable list ofEmailAddress.static List<EmailAddress> parseAddressList(String addressList, Consumer<? super String> ifInvalid) ParsesaddressListaccording to RFC 5322 and returns an immutable list ofEmailAddress, with invalid entries passed to theifInvalidconsumer.toString()Returns the full email address, in the form oflocal-part@domainor"display name" <local-part@domain>.Returns the display name in Unicode (with any RFC 2047 encoded-words decoded), orOptional.empty()if no display name is present.Returns the domain in Unicode.user()Returns the "user" part of the local-part before the first+separator, according to RFC 5233 subaddressing.withDisplayName(String displayName) Returns an otherwise equivalentEmailAddressbut withdisplayName.
-
Field Details
-
PARSER
The parser for email address, according to RFC 5322, and supporting BMP characters.Prefer using the
of(java.lang.String, java.lang.String)convenience method. This constant is to be used for composition, for example to parse a group addresses:Parser.sequence( Parser.word().followedBy(":"), EmailAddress.PARSER.zeroOrMoreDelimitedBy(",").followedBy(";"), GroupAddress::new);
-
-
Constructor Details
-
EmailAddress
Prefer using theof(java.lang.String, java.lang.String)factory method. You can callwithDisplayName(java.lang.String)to optionally attach a display name.
-
-
Method Details
-
withDisplayName
Returns an otherwise equivalentEmailAddressbut withdisplayName. -
unicodeDisplayName
Returns the display name in Unicode (with any RFC 2047 encoded-words decoded), orOptional.empty()if no display name is present.To prevent visual spoofing and phishing attacks in standard rendering, the main
displayName()component is kept in its raw transport-safe encoded form. This method provides a safe, explicit opt-in to decode the display name.Only standard, ASCII-compatible charsets (specifically UTF-8, ISO-8859-1, and US-ASCII) are decoded, guarding against null-byte injection exploits in downstream systems. Unsupported charsets or syntactically malformed encoded-words are safely left in their encoded form.
- Since:
- 10.3.1
-
of
For example:EmailAddress.of("user", "mycompany.com"). -
of
Parsesaddressand throwsParser.ParseExceptionif failed.- Since:
- 9.9.8
-
address
Returns theaddr-spec, in the form ofuser@mycompany.com. -
user
Returns the "user" part of the local-part before the first+separator, according to RFC 5233 subaddressing. If no+is present, the fulllocalPartis returned.- Since:
- 10.3
-
alias
-
unicodeDomain
-
hasI18nDomain
public boolean hasI18nDomain()Returns true if this address has an internationalized domain, in which casedomain()will be puny-coded.- Since:
- 10.3
-
toString
-
parse
@Deprecated @InlineMe(replacement="EmailAddress.of(address)", imports="com.google.common.labs.email.EmailAddress") public static EmailAddress parse(String address) Deprecated.Useof(String)instead -
parseAddressList
ParsesaddressListaccording to RFC 5322 and returns an immutable list ofEmailAddress.Both comma (
,) and semicolon (;) are supported as delimiters, with whitespaces ignored. Trailing delimiters are allowed.Empty input will result in an empty list being returned.
Note that if your address list may contain invalid entries, and you'd want to ignore them instead of failing, use
parseAddressList(String, Consumer).- Throws:
Parser.ParseException- ifaddressListis invalid
-
parseAddressList
public static List<EmailAddress> parseAddressList(String addressList, Consumer<? super String> ifInvalid) ParsesaddressListaccording to RFC 5322 and returns an immutable list ofEmailAddress, with invalid entries passed to theifInvalidconsumer.For example,
List<EmailAddress> addresses = parseAddressList(inputAddressList, logger::log);Both comma (
,) and semicolon (;) are supported as delimiters, with whitespaces ignored. Trailing delimiters are allowed.Empty input will result in an empty list being returned.
- Since:
- 10.3
-
hashCode
-
equals
Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. All components in this record class are compared withObjects::equals(Object,Object). -
localPart
-
domain
-
displayName
Returns the value of thedisplayNamerecord component.- Returns:
- the value of the
displayNamerecord component
-
of(String)instead