WordPress and PHP core
The is_email()
function Source is a typical WordPress implementation and does not work completely with what the RFC 6531 allows. One reason might be, that the default PHP FILTER_VALIDATE_EMAIL
constant for filter_var()
isn't much better at validating something according to the The Internet Engineering Task Force (IETF®) guidelines.
Standards
Point is that the RFC 6531 allows "Unicode characters beyond the ASCII range". Namely those are (for the local part - before the @
):
- Uppercase and lowercase English letters (a–z, A–Z) (ASCII: 65–90, 97–122)
- Digits
0
to 9
(ASCII: 48–57)
- These special characters:
! # $ % & ' * + - / = ? ^ _ ` { | } ~
- Character
.
(dot, period, full stop) (ASCII: 46) provided that it is not the first or last character, and provided also that it does not appear consecutively (e.g. [email protected]
is not allowed).
- Special characters are allowed with restrictions. They are:
- Space and
"(),:;<>@[\]
(ASCII: 32, 34, 40, 41, 44, 58, 59, 60, 62, 64, 91–93)
- The restrictions for special characters are that they must only be used when contained between quotation marks, and that 2 of them (the backslash \ and quotation mark " (ASCII: 92, 34)) must also be preceded by a backslash
\
(e.g. "\\"
and "\""
).
- Comments are allowed with parentheses at either end of the local part; e.g.
john.smith(comment)@example.com
and (comment)[email protected]
are both equivalent to "[email protected]"
, but john.(comment)[email protected]
would be invalid.
- International characters above
U+007F
, encoded as UTF-8, are permitted by RFC 6531, though mail systems may restrict which characters to use when assigning local parts.
and for the global/domain part:
The domain name part of an email address has to conform to strict guidelines: it must match the requirements for a hostname, consisting of letters, digits, hyphens and dots. In addition, the domain part may be an IP address literal, surrounded by square braces, such as jsmith@[192.168.2.1]
or jsmith@[IPv6:2001:db8::1]
[…]
Source: Wikipedia
What is valid?
This can lead to strange, but valid e-mail addresses like the following:
(comment)[email protected]
"this is v@lid!"@example.com
"much.more unusual"@example.com
postbox@com
admin@mailserver1
"()<>[]:,;\\@\"\\\\!#$%&\'*+-/=?^_`{}| ~.a"@example.org
" "@example.org
Source: php.net / author [email protected] – example fixed by author of this post
Limits
There are also local & domain length limits:
The format of email addresses is local-part@domain
where the local-part may be up to 64 characters long and the domain name may have a maximum of 253 characters – but the maximum of 256-character length of a forward or reverse path restricts the entire email address to be no more than 254 characters long.[2] The formal definitions are in RFC 5322 (sections 3.2.3 and 3.4.1) and RFC 5321 – with a more readable form given in the informational RFC 3696[3] and the associated errata.
Source: Wikipedia
WordPress restrictions
And this is what WordPress checks for:
- Test for the minimum length the email can be:
strlen( $email ) < 3
- Test for an @ character after the first position:
strpos( $email, '@', 1 ) === false
- Test for invalid characters:
!preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local )
- Test for sequences of periods:
preg_match( '/\.{2,}/', $domain )
- Test for leading and trailing periods and whitespace:
trim( $domain, " \t\n\r\0\x0B." ) !== $domain
- Assume the domain will have at least two subs:
$subs = explode( '.', $domain );
and then
2 > count( $subs )
trim( $sub, " \t\n\r\0\x0B-" ) !== $sub
!preg_match('/^[a-z0-9-]+$/i', $sub )
Source: WP Core v4.0
Filters & custom validation
All above mentioned cases will trigger is_email()
to return false. The result is filter-able (a callback can be attached) and the filter will have three arguments, where the last argument is the reason. Example:
return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
which means that you can override results returned by specific checks.
This allows you to add special checks, for example to allow Umlaut-domains, TLD-only domain parts, etc.
Conclusion
WordPress is safe for most cases, but more restrictive as mail servers actually have to be to be RFC compliant. Keep in mind that not every mail server will align with the RF 6531 guidelines.
Edit
Funny sidefact: There are two related functions inside ~/wp-includes/formatting
: is_email()
and sanitize_email()
. They are practically the same function. I have no idea why someone decided that it would be a good idea to copy the function contents from one over to another instead of just adding the one as callback to the filters the other provides. As is_email()
since v0.71 and sanitize_email()
since v1.5 are the same, I personally would use the later as you get a cleaned string. Note that is_email()
even states that it isn't RFC compliant.