/std/net/isemail.d
http://github.com/jcd/phobos · D · 2073 lines · 1777 code · 222 blank · 74 comment · 280 complexity · a1982edccdc56ec3ff1ce8370f71a4cd MD5 · raw file
Large files are truncated click here to view the full file
- /**
- * Validates an email address according to RFCs 5321, 5322 and others.
- *
- * Authors: Dominic Sayers <dominic@sayers.cc>, Jacob Carlborg
- * Copyright: Dominic Sayers, Jacob Carlborg 2008-.
- * Test schema documentation: Copyright © 2011, Daniel Marschall
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
- * Version: 3.0.13 - Version 3.0 of the original PHP implementation: $(LINK http://www.dominicsayers.com/isemail)
- *
- * Standards:
- * $(UL
- * $(LI RFC 5321)
- * $(LI RFC 5322)
- * )
- *
- * References:
- * $(UL
- * $(LI $(LINK http://www.dominicsayers.com/isemail))
- * $(LI $(LINK http://tools.ietf.org/html/rfc5321))
- * $(LI $(LINK http://tools.ietf.org/html/rfc5322))
- * )
- *
- * Source: $(PHOBOSSRC std/net/_isemail.d)
- */
- module std.net.isemail;
- import std.algorithm : cmp, equal, uniq, filter, contains = canFind;
- import std.range : ElementType;
- import std.array;
- import std.ascii;
- import std.conv;
- import std.exception : enforce;
- import std.regex;
- import std.string;
- import std.traits;
- import std.utf;
- import std.uni;
- /**
- * Check that an email address conforms to RFCs 5321, 5322 and others.
- *
- * As of Version 3.0, we are now distinguishing clearly between a Mailbox as defined
- * by RFC 5321 and an addr-spec as defined by RFC 5322. Depending on the context,
- * either can be regarded as a valid email address. The RFC 5321 Mailbox specification
- * is more restrictive (comments, white space and obsolete forms are not allowed).
- *
- * Note: The DNS check is currently not implemented.
- *
- * Params:
- * email = The email address to check
- * checkDNS = If CheckDns.yes then a DNS check for MX records will be made
- * errorLevel = Determines the boundary between valid and invalid addresses.
- * Status codes above this number will be returned as-is,
- * status codes below will be returned as EmailStatusCode.valid.
- * Thus the calling program can simply look for EmailStatusCode.valid
- * if it is only interested in whether an address is valid or not. The
- * $(D_PARAM errorLevel) will determine how "picky" isEmail() is about
- * the address.
- *
- * If omitted or passed as EmailStatusCode.none then isEmail() will
- * not perform any finer grained error checking and an address is
- * either considered valid or not. Email status code will either be
- * EmailStatusCode.valid or EmailStatusCode.error.
- *
- * Returns: an EmailStatus, indicating the status of the email address.
- */
- EmailStatus isEmail (Char) (const(Char)[] email, CheckDns checkDNS = CheckDns.no,
- EmailStatusCode errorLevel = EmailStatusCode.none) if (isSomeChar!(Char))
- {
- alias const(Char)[] tstring;
- enum defaultThreshold = 16;
- int threshold;
- bool diagnose;
- if (errorLevel == EmailStatusCode.any || errorLevel == EmailStatusCode.none)
- {
- threshold = EmailStatusCode.valid;
- diagnose = errorLevel == EmailStatusCode.any;
- }
- else
- {
- diagnose = true;
- switch (errorLevel)
- {
- case EmailStatusCode.warning: threshold = defaultThreshold; break;
- case EmailStatusCode.error: threshold = EmailStatusCode.valid; break;
- default: threshold = errorLevel;
- }
- }
- auto returnStatus = [EmailStatusCode.valid];
- auto context = EmailPart.componentLocalPart;
- auto contextStack = [context];
- auto contextPrior = context;
- tstring token = "";
- tstring tokenPrior = "";
- tstring[EmailPart] parseData = [EmailPart.componentLocalPart : "", EmailPart.componentDomain : ""];
- tstring[][EmailPart] atomList = [EmailPart.componentLocalPart : [""], EmailPart.componentDomain : [""]];
- auto elementCount = 0;
- auto elementLength = 0;
- auto hyphenFlag = false;
- auto endOrDie = false;
- auto crlfCount = int.min; // int.min == not defined
- foreach (ref i, e ; email)
- {
- token = email.get(i, e);
- switch (context)
- {
- case EmailPart.componentLocalPart:
- switch (token)
- {
- case Token.openParenthesis:
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.comment :
- EmailStatusCode.deprecatedComment;
- else
- {
- returnStatus ~= EmailStatusCode.comment;
- endOrDie = true;
- }
- contextStack ~= context;
- context = EmailPart.contextComment;
- break;
- case Token.dot:
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.errorDotStart :
- EmailStatusCode.errorConsecutiveDots;
- else
- {
- if (endOrDie)
- returnStatus ~= EmailStatusCode.deprecatedLocalPart;
- }
- endOrDie = false;
- elementLength = 0;
- elementCount++;
- parseData[EmailPart.componentLocalPart] ~= token;
- if (elementCount >= atomList[EmailPart.componentLocalPart].length)
- atomList[EmailPart.componentLocalPart] ~= "";
- else
- atomList[EmailPart.componentLocalPart][elementCount] = "";
- break;
- case Token.doubleQuote:
- if (elementLength == 0)
- {
- returnStatus ~= elementCount == 0 ? EmailStatusCode.rfc5321QuotedString :
- EmailStatusCode.deprecatedLocalPart;
- parseData[EmailPart.componentLocalPart] ~= token;
- atomList[EmailPart.componentLocalPart][elementCount] ~= token;
- elementLength++;
- endOrDie = true;
- contextStack ~= context;
- context = EmailPart.contextQuotedString;
- }
- else
- returnStatus ~= EmailStatusCode.errorExpectingText;
- break;
- case Token.cr:
- case Token.space:
- case Token.tab:
- if ((token == Token.cr) && ((++i == email.length) || (email.get(i, e) != Token.lf)))
- {
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- }
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.foldingWhitespace :
- EmailStatusCode.deprecatedFoldingWhitespace;
- else
- endOrDie = true;
- contextStack ~= context;
- context = EmailPart.contextFoldingWhitespace;
- tokenPrior = token;
- break;
- case Token.at:
- enforce(contextStack.length == 1, "Unexpected item on context stack");
- if (parseData[EmailPart.componentLocalPart] == "")
- returnStatus ~= EmailStatusCode.errorNoLocalPart;
- else if (elementLength == 0)
- returnStatus ~= EmailStatusCode.errorDotEnd;
- else if (parseData[EmailPart.componentLocalPart].length > 64)
- returnStatus ~= EmailStatusCode.rfc5322LocalTooLong;
- else if (contextPrior == EmailPart.contextComment ||
- contextPrior == EmailPart.contextFoldingWhitespace)
- returnStatus ~= EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt;
- context = EmailPart.componentDomain;
- contextStack = [context];
- elementCount = 0;
- elementLength = 0;
- endOrDie = false;
- break;
- default:
- if (endOrDie)
- {
- switch (contextPrior)
- {
- case EmailPart.contextComment:
- case EmailPart.contextFoldingWhitespace:
- returnStatus ~= EmailStatusCode.errorTextAfterCommentFoldingWhitespace;
- break;
- case EmailPart.contextQuotedString:
- returnStatus ~= EmailStatusCode.errorTextAfterQuotedString;
- break;
- default:
- throw new Exception("More text found where none is allowed, but unrecognised prior "
- "context: " ~ to!(string)(contextPrior));
- }
- }
- else
- {
- contextPrior = context;
- auto c = token.front;
- if (c < '!' || c > '~' || c == '\n' || Token.specials.contains(token))
- returnStatus ~= EmailStatusCode.errorExpectingText;
- parseData[EmailPart.componentLocalPart] ~= token;
- atomList[EmailPart.componentLocalPart][elementCount] ~= token;
- elementLength++;
- }
- }
- break;
- case EmailPart.componentDomain:
- switch (token)
- {
- case Token.openParenthesis:
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt
- : EmailStatusCode.deprecatedComment;
- else
- {
- returnStatus ~= EmailStatusCode.comment;
- endOrDie = true;
- }
- contextStack ~= context;
- context = EmailPart.contextComment;
- break;
- case Token.dot:
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.errorDotStart :
- EmailStatusCode.errorConsecutiveDots;
- else if (hyphenFlag)
- returnStatus ~= EmailStatusCode.errorDomainHyphenEnd;
- else
- {
- if (elementLength > 63)
- returnStatus ~= EmailStatusCode.rfc5322LabelTooLong;
- }
- endOrDie = false;
- elementLength = 0,
- elementCount++;
- //atomList[EmailPart.componentDomain][elementCount] = "";
- atomList[EmailPart.componentDomain] ~= "";
- parseData[EmailPart.componentDomain] ~= token;
- break;
- case Token.openBracket:
- if (parseData[EmailPart.componentDomain] == "")
- {
- endOrDie = true;
- elementLength++;
- contextStack ~= context;
- context = EmailPart.componentLiteral;
- parseData[EmailPart.componentDomain] ~= token;
- atomList[EmailPart.componentDomain][elementCount] ~= token;
- parseData[EmailPart.componentLiteral] = "";
- }
- else
- returnStatus ~= EmailStatusCode.errorExpectingText;
- break;
- case Token.cr:
- case Token.space:
- case Token.tab:
- if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf))
- {
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- }
- if (elementLength == 0)
- returnStatus ~= elementCount == 0 ? EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt
- : EmailStatusCode.deprecatedFoldingWhitespace;
- else
- {
- returnStatus ~= EmailStatusCode.foldingWhitespace;
- endOrDie = true;
- }
- contextStack ~= context;
- context = EmailPart.contextFoldingWhitespace;
- tokenPrior = token;
- break;
- default:
- if (endOrDie)
- {
- switch (contextPrior)
- {
- case EmailPart.contextComment:
- case EmailPart.contextFoldingWhitespace:
- returnStatus ~= EmailStatusCode.errorTextAfterCommentFoldingWhitespace;
- break;
- case EmailPart.componentLiteral:
- returnStatus ~= EmailStatusCode.errorTextAfterDomainLiteral;
- break;
- default:
- throw new Exception("More text found where none is allowed, but unrecognised prior "
- "context: " ~ to!(string)(contextPrior));
- }
- }
- auto c = token.front;
- hyphenFlag = false;
- if (c < '!' || c > '~' || Token.specials.contains(token))
- returnStatus ~= EmailStatusCode.errorExpectingText;
- else if (token == Token.hyphen)
- {
- if (elementLength == 0)
- returnStatus ~= EmailStatusCode.errorDomainHyphenStart;
- hyphenFlag = true;
- }
- else if (!((c > '/' && c < ':') || (c > '@' && c < '[') || (c > '`' && c < '{')))
- returnStatus ~= EmailStatusCode.rfc5322Domain;
- parseData[EmailPart.componentDomain] ~= token;
- atomList[EmailPart.componentDomain][elementCount] ~= token;
- elementLength++;
- }
- break;
- case EmailPart.componentLiteral:
- switch (token)
- {
- case Token.closeBracket:
- if (returnStatus.max() < EmailStatusCode.deprecated_)
- {
- auto maxGroups = 8;
- size_t index = -1;
- auto addressLiteral = parseData[EmailPart.componentLiteral];
- enum regexStr = `\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}`~
- `(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`;
- auto matchesIp = array(addressLiteral.match(regex!tstring(regexStr)).captures);
- if (!matchesIp.empty)
- {
- index = addressLiteral.lastIndexOf(matchesIp.front);
- if (index != 0)
- addressLiteral = addressLiteral.substr(0, index) ~ "0:0";
- }
- if (index == 0)
- returnStatus ~= EmailStatusCode.rfc5321AddressLiteral;
- else if (addressLiteral.compareFirstN(Token.ipV6Tag, 5, true))
- returnStatus ~= EmailStatusCode.rfc5322DomainLiteral;
- else
- {
- auto ipV6 = addressLiteral.substr(5);
- matchesIp = ipV6.split(Token.colon);
- auto groupCount = matchesIp.length;
- index = ipV6.indexOf(Token.doubleColon);
- if (index == -1)
- {
- if (groupCount != maxGroups)
- returnStatus ~= EmailStatusCode.rfc5322IpV6GroupCount;
- }
- else
- {
- if (index != ipV6.lastIndexOf(Token.doubleColon))
- returnStatus ~= EmailStatusCode.rfc5322IpV6TooManyDoubleColons;
- else
- {
- if (index == 0 || index == (ipV6.length - 2))
- maxGroups++;
- if (groupCount > maxGroups)
- returnStatus ~= EmailStatusCode.rfc5322IpV6MaxGroups;
- else if (groupCount == maxGroups)
- returnStatus ~= EmailStatusCode.rfc5321IpV6Deprecated;
- }
- }
- if (ipV6.substr(0, 1) == Token.colon && ipV6.substr(1, 1) != Token.colon)
- returnStatus ~= EmailStatusCode.rfc5322IpV6ColonStart;
- else if (ipV6.substr(-1) == Token.colon && ipV6.substr(-2, -1) != Token.colon)
- returnStatus ~= EmailStatusCode.rfc5322IpV6ColonEnd;
- else if (!matchesIp.grep(regex!(tstring)(`^[0-9A-Fa-f]{0,4}$`), true).empty)
- returnStatus ~= EmailStatusCode.rfc5322IpV6BadChar;
- else
- returnStatus ~= EmailStatusCode.rfc5321AddressLiteral;
- }
- }
- else
- returnStatus ~= EmailStatusCode.rfc5322DomainLiteral;
- parseData[EmailPart.componentDomain] ~= token;
- atomList[EmailPart.componentDomain][elementCount] ~= token;
- elementLength++;
- contextPrior = context;
- context = contextStack.pop();
- break;
- case Token.backslash:
- returnStatus ~= EmailStatusCode.rfc5322DomainLiteralObsoleteText;
- contextStack ~= context;
- context = EmailPart.contextQuotedPair;
- break;
- case Token.cr:
- case Token.space:
- case Token.tab:
- if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf))
- {
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- }
- returnStatus ~= EmailStatusCode.foldingWhitespace;
- contextStack ~= context;
- context = EmailPart.contextFoldingWhitespace;
- tokenPrior = token;
- break;
- default:
- auto c = token.front;
- if (c > AsciiToken.delete_ || c == '\0' || token == Token.openBracket)
- {
- returnStatus ~= EmailStatusCode.errorExpectingDomainText;
- break;
- }
- else if (c < '!' || c == AsciiToken.delete_ )
- returnStatus ~= EmailStatusCode.rfc5322DomainLiteralObsoleteText;
- parseData[EmailPart.componentLiteral] ~= token;
- parseData[EmailPart.componentDomain] ~= token;
- atomList[EmailPart.componentDomain][elementCount] ~= token;
- elementLength++;
- }
- break;
- case EmailPart.contextQuotedString:
- switch (token)
- {
- case Token.backslash:
- contextStack ~= context;
- context = EmailPart.contextQuotedPair;
- break;
- case Token.cr:
- case Token.tab:
- if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf))
- {
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- }
- parseData[EmailPart.componentLocalPart] ~= Token.space;
- atomList[EmailPart.componentLocalPart][elementCount] ~= Token.space;
- elementLength++;
- returnStatus ~= EmailStatusCode.foldingWhitespace;
- contextStack ~= context;
- context = EmailPart.contextFoldingWhitespace;
- tokenPrior = token;
- break;
- case Token.doubleQuote:
- parseData[EmailPart.componentLocalPart] ~= token;
- atomList[EmailPart.componentLocalPart][elementCount] ~= token;
- elementLength++;
- contextPrior = context;
- context = contextStack.pop();
- break;
- default:
- auto c = token.front;
- if (c > AsciiToken.delete_ || c == '\0' || c == '\n')
- returnStatus ~= EmailStatusCode.errorExpectingQuotedText;
- else if (c < ' ' || c == AsciiToken.delete_)
- returnStatus ~= EmailStatusCode.deprecatedQuotedText;
- parseData[EmailPart.componentLocalPart] ~= token;
- atomList[EmailPart.componentLocalPart][elementCount] ~= token;
- elementLength++;
- }
- break;
- case EmailPart.contextQuotedPair:
- auto c = token.front;
- if (c > AsciiToken.delete_)
- returnStatus ~= EmailStatusCode.errorExpectingQuotedPair;
- else if (c < AsciiToken.unitSeparator && c != AsciiToken.horizontalTab || c == AsciiToken.delete_)
- returnStatus ~= EmailStatusCode.deprecatedQuotedPair;
- contextPrior = context;
- context = contextStack.pop();
- token = Token.backslash ~ token;
- switch (context)
- {
- case EmailPart.contextComment: break;
- case EmailPart.contextQuotedString:
- parseData[EmailPart.componentLocalPart] ~= token;
- atomList[EmailPart.componentLocalPart][elementCount] ~= token;
- elementLength += 2;
- break;
- case EmailPart.componentLiteral:
- parseData[EmailPart.componentDomain] ~= token;
- atomList[EmailPart.componentDomain][elementCount] ~= token;
- elementLength += 2;
- break;
- default:
- throw new Exception("Quoted pair logic invoked in an invalid context: " ~ to!(string)(context));
- }
- break;
- case EmailPart.contextComment:
- switch (token)
- {
- case Token.openParenthesis:
- contextStack ~= context;
- context = EmailPart.contextComment;
- break;
- case Token.closeParenthesis:
- contextPrior = context;
- context = contextStack.pop();
- break;
- case Token.backslash:
- contextStack ~= context;
- context = EmailPart.contextQuotedPair;
- break;
- case Token.cr:
- case Token.space:
- case Token.tab:
- if (token == Token.cr && (++i == email.length || email.get(i, e) != Token.lf))
- {
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- }
- returnStatus ~= EmailStatusCode.foldingWhitespace;
- contextStack ~= context;
- context = EmailPart.contextFoldingWhitespace;
- tokenPrior = token;
- break;
- default:
- auto c = token.front;
- if (c > AsciiToken.delete_ || c == '\0' || c == '\n')
- {
- returnStatus ~= EmailStatusCode.errorExpectingCommentText;
- break;
- }
- else if (c < ' ' || c == AsciiToken.delete_)
- returnStatus ~= EmailStatusCode.deprecatedCommentText;
- }
- break;
- case EmailPart.contextFoldingWhitespace:
- if (tokenPrior == Token.cr)
- {
- if (token == Token.cr)
- {
- returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrflX2;
- break;
- }
- if (crlfCount != int.min) // int.min == not defined
- {
- if (++crlfCount > 1)
- returnStatus ~= EmailStatusCode.deprecatedFoldingWhitespace;
- }
- else
- crlfCount = 1;
- }
- switch (token)
- {
- case Token.cr:
- if (++i == email.length || email.get(i, e) != Token.lf)
- returnStatus ~= EmailStatusCode.errorCrNoLf;
- break;
- case Token.space:
- case Token.tab:
- break;
- default:
- if (tokenPrior == Token.cr)
- {
- returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrLfEnd;
- break;
- }
- crlfCount = int.min; // int.min == not defined
- contextPrior = context;
- context = contextStack.pop();
- i--;
- break;
- }
- tokenPrior = token;
- break;
- default:
- throw new Exception("Unkown context: " ~ to!(string)(context));
- }
- if (returnStatus.max() > EmailStatusCode.rfc5322)
- break;
- }
- if (returnStatus.max() < EmailStatusCode.rfc5322)
- {
- if (context == EmailPart.contextQuotedString)
- returnStatus ~= EmailStatusCode.errorUnclosedQuotedString;
- else if (context == EmailPart.contextQuotedPair)
- returnStatus ~= EmailStatusCode.errorBackslashEnd;
- else if (context == EmailPart.contextComment)
- returnStatus ~= EmailStatusCode.errorUnclosedComment;
- else if (context == EmailPart.componentLiteral)
- returnStatus ~= EmailStatusCode.errorUnclosedDomainLiteral;
- else if (token == Token.cr)
- returnStatus ~= EmailStatusCode.errorFoldingWhitespaceCrLfEnd;
- else if (parseData[EmailPart.componentDomain] == "")
- returnStatus ~= EmailStatusCode.errorNoDomain;
- else if (elementLength == 0)
- returnStatus ~= EmailStatusCode.errorDotEnd;
- else if (hyphenFlag)
- returnStatus ~= EmailStatusCode.errorDomainHyphenEnd;
- else if (parseData[EmailPart.componentDomain].length > 255)
- returnStatus ~= EmailStatusCode.rfc5322DomainTooLong;
- else if ((parseData[EmailPart.componentLocalPart] ~ Token.at ~ parseData[EmailPart.componentDomain]).length >
- 254)
- returnStatus ~= EmailStatusCode.rfc5322TooLong;
- else if (elementLength > 63)
- returnStatus ~= EmailStatusCode.rfc5322LabelTooLong;
- }
- auto dnsChecked = false;
- if (checkDNS == CheckDns.yes && returnStatus.max() < EmailStatusCode.dnsWarning)
- {
- assert(false, "DNS check is currently not implemented");
- }
- if (!dnsChecked && returnStatus.max() < EmailStatusCode.dnsWarning)
- {
- if (elementCount == 0)
- returnStatus ~= EmailStatusCode.rfc5321TopLevelDomain;
- if (isNumeric(atomList[EmailPart.componentDomain][elementCount].front))
- returnStatus ~= EmailStatusCode.rfc5321TopLevelDomainNumeric;
- }
- returnStatus = array(uniq(returnStatus));
- auto finalStatus = returnStatus.max();
- if (returnStatus.length != 1)
- returnStatus.popFront();
- parseData[EmailPart.status] = to!(tstring)(returnStatus);
- if (finalStatus < threshold)
- finalStatus = EmailStatusCode.valid;
- if (!diagnose)
- finalStatus = finalStatus < threshold ? EmailStatusCode.valid : EmailStatusCode.error;
- auto valid = finalStatus == EmailStatusCode.valid;
- tstring localPart = "";
- tstring domainPart = "";
- if (auto value = EmailPart.componentLocalPart in parseData)
- localPart = *value;
- if (auto value = EmailPart.componentDomain in parseData)
- domainPart = *value;
- return EmailStatus(valid, to!(string)(localPart), to!(string)(domainPart), finalStatus);
- }
- unittest
- {
- assert(``.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain);
- assert(`test`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain);
- assert(`@`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart);
- assert(`test@`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain);
- // assert(`test@io`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid,
- // `io. currently has an MX-record (Feb 2011). Some DNS setups seem to find it, some don't.`
- // ` If you don't see the MX for io. then try setting your DNS server to 8.8.8.8 (the Google DNS server)`);
- assert(`@io`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart,
- `io. currently has an MX-record (Feb 2011)`);
- assert(`@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoLocalPart);
- assert(`test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test@nominet.org.uk`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test@about.museum`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`a@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- //assert(`test@e.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord);
- // DNS check is currently not implemented
- //assert(`test@iana.a`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord);
- // DNS check is currently not implemented
- assert(`test.test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`.test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotStart);
- assert(`test.@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotEnd);
- assert(`test..iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorConsecutiveDots);
- assert(`test_exa-mple.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorNoDomain);
- assert("!#$%&`*+/=?^`{|}~@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test\@test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingText);
- assert(`123@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test@123.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test@iana.123`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321TopLevelDomainNumeric);
- assert(`test@255.255.255.255`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321TopLevelDomainNumeric);
- assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong);
- // assert(`test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com`.isEmail(CheckDns.no,
- // EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord);
- // DNS check is currently not implemented
- assert(`test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LabelTooLong);
- assert(`test@mason-dixon.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- assert(`test@-iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorDomainHyphenStart);
- assert(`test@iana-.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorDomainHyphenEnd);
- assert(`test@g--a.com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid);
- //assert(`test@iana.co-uk`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- //EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented
- assert(`test@.iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotStart);
- assert(`test@iana.org.`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorDotEnd);
- assert(`test@iana..com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorConsecutiveDots);
- //assert(`a@a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z`
- // `.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z`
- // `.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- // EmailStatusCode.dnsWarningNoRecord); // DNS check is currently not implemented
- // assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyz`
- // `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`
- // `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghi`.isEmail(CheckDns.no,
- // EmailStatusCode.any).statusCode == EmailStatusCode.dnsWarningNoRecord);
- // DNS check is currently not implemented
- assert(`abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyz`
- `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`
- `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghij`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322TooLong);
- assert(`a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyz`
- `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`
- `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hij`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322TooLong);
- assert(`a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyz`
- `abcdefghijklmnopqrstuvwxyzabcdefghikl.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.`
- `abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.hijk`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322DomainTooLong);
- assert(`"test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321QuotedString);
- assert(`""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString);
- assert(`"""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText);
- assert(`"\a"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString);
- assert(`"\""@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString);
- assert(`"\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedQuotedString);
- assert(`"\\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321QuotedString);
- assert(`test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.errorExpectingText);
- assert(`"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedQuotedString);
- assert(`"test"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorTextAfterQuotedString);
- assert(`test"text"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingText);
- assert(`"test""test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingText);
- assert(`"test"."test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedLocalPart);
- assert(`"test\ test"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321QuotedString);
- assert(`"test".test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedLocalPart);
- assert("\"test\u0000\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingQuotedText);
- assert("\"test\\\u0000\"@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedQuotedPair);
- assert(`"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj"@iana.org`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong,
- `Quotes are still part of the length restriction`);
- assert(`"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\h"@iana.org`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322LocalTooLong,
- `Quoted pair is still part of the length restriction`);
- assert(`test@[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@a[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingText);
- assert(`test@[255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322DomainLiteral);
- assert(`test@[255.255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322DomainLiteral);
- assert(`test@[255.255.255.256]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322DomainLiteral);
- assert(`test@[1111:2222:3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322DomainLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322IpV6GroupCount);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode
- == EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6BadChar);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::8888]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321IpV6Deprecated);
- assert(`test@[IPv6:1111:2222:3333:4444:5555::8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6MaxGroups);
- assert(`test@[IPv6::3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322IpV6ColonStart);
- assert(`test@[IPv6:::3333:4444:5555:6666:7777:8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111::4444:5555::8888]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322IpV6TooManyDoubleColons);
- assert(`test@[IPv6:::]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6GroupCount);
- assert(`test@[IPv6:1111:2222:3333:4444::255.255.255.255]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5321AddressLiteral);
- assert(`test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.rfc5322IpV6MaxGroups);
- assert(`test@[IPv6:1111:2222:3333:4444:::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode
- == EmailStatusCode.rfc5322IpV6TooManyDoubleColons);
- assert(`test@[IPv6::255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322IpV6ColonStart);
- assert(` test @iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt);
- assert(`test@ iana .com`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt);
- assert(`test . test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedFoldingWhitespace);
- assert("\u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.foldingWhitespace, `Folding whitespace`);
- assert("\u000D\u000A \u000D\u000A test@iana.org".isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedFoldingWhitespace, `FWS with one line composed entirely of WSP`
- ` -- only allowed as obsolete FWS (someone might allow only non-obsolete FWS)`);
- assert(`(comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.comment);
- assert(`((comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedComment);
- assert(`(comment(comment))test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.comment);
- assert(`test@(comment)iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt);
- assert(`test(comment)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorTextAfterCommentFoldingWhitespace);
- assert(`test@(comment)[255.255.255.255]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt);
- assert(`(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.comment);
- assert(`test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghikl.com`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.deprecatedCommentFoldingWhitespaceNearAt);
- assert(`(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyz`
- `abcdefghijklmnopqrstuvwxyzabcdefghik.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.`
- `abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstu`.isEmail(CheckDns.no,
- EmailStatusCode.any).statusCode == EmailStatusCode.comment);
- assert("test@iana.org\u000A".isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorExpectingText);
- assert(`test@xn--hxajbheg2az3al.xn--jxalpdlp`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.valid, `A valid IDN from ICANN's <a href="http://idn.icann.org/#The_example.test_names">`
- `IDN TLD evaluation gateway</a>`);
- assert(`xn--test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode == EmailStatusCode.valid,
- `RFC 3490: "unless the email standards are revised to invite the use of IDNA for local parts, a domain label`
- ` that holds the local part of an email address SHOULD NOT begin with the ACE prefix, and even if it does,`
- ` it is to be interpreted literally as a local part that happens to begin with the ACE prefix"`);
- assert(`test@iana.org-`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorDomainHyphenEnd);
- assert(`"test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedQuotedString);
- assert(`(test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedComment);
- assert(`test@(iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedComment);
- assert(`test@[1.2.3.4`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedDomainLiteral);
- assert(`"test\"@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedQuotedString);
- assert(`(comment\)test@iana.org`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedComment);
- assert(`test@iana.org(comment\)`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorUnclosedComment);
- assert(`test@iana.org(comment\`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorBackslashEnd);
- assert(`test@[RFC-5322-domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.rfc5322DomainLiteral);
- assert(`test@[RFC-5322]-domain-literal]`.isEmail(CheckDns.no, EmailStatusCode.any).statusCode ==
- EmailStatusCode.errorTextAfterDomainLiteral);
- assert(`test@[RFC-5322-…