Skip to content

Email validation reference

Arcjet lets you validate and verify an email address. This is useful for preventing users from signing up with fake email addresses and can significantly reduce the amount of spam or fraudulent accounts.

The first step is to validate the email address syntax. This runs locally within the SDK and validates the email address is in the correct format. Validation is performed against several RFCs with modifications to exclude email addresses you wouldn’t expect signing up to a real application, such as local domains.

Two of the validation options are configurable. The first is whether two parts of the domain are required, which defaults to required. The second is whether domain literals such as example@[127.0.0.1] are allowed, which defaults to not allowed. The SDK documentation describes how to configure them.

Internally, validation is implemented using the open source email_address Crate.

If an email address fails validation, Arcjet provides one of the following errors:

  • MissingTopLevelDomain: The email address didn’t contain at least 2 domain segments – it must contain at least the domain name and TLD.
  • InvalidDomainLiteral: The address contained a domain literal, such as foo@[123.456.789.0], which Arcjet does not support.
  • MissingSeparator: The @ character was missing between the local part and domain.
  • InvalidCharacter: The email address contained an invalid character.
  • LocalPartEmpty: The local part of the email address must contain at least 1 character.
  • LocalPartTooLong: The local part has a maximum length of 64 characters, as per RFC 3696.
  • DomainEmpty: The domain of the email address must contain at least 1 character.
  • DomainTooLong: The domain has a maximum length of 254 characters, as per RFC 3696 errata 1690.
  • SubDomainEmpty: One or more domain segments, separated by the . character, are empty.
  • SubDomainTooLong: One or more domain segments, separated by the . character, are longer than 63 characters, as per RFC 1034.

If the email syntax is valid, the SDK passes the email address to the Arcjet cloud API for verification. This performs several checks:

  • MX validation: checks whether the domain has valid MX records.
  • Email type: checks whether the email address is a free, disposable, or role-based email address.
  • Has Gravatar: checks whether the email address has a Gravatar image associated with it. This is useful for checking if the email address is a real person.

This metadata is returned as part of the Arcjet SDK response so you can decide what to do next. For example, you might decide to block signups from domains without MX records and from disposable email addresses, but add a flag to manually review those from free email providers.

The Arcjet SDK provides an analysis of the email type, returning one or several of the following:

  • Disposable: The email address is disposable, which means it’s registered to a service that allows throwaway email addresses. Although these are sometimes used for privacy, they are also often used for spam signups or fraudulent activity when combined with a transaction, such as attempting to use a credit card. We recommend blocking these in higher risk scenarios.
  • Free: The email address is registered to a free email service. These are very common, such as GMail or Yahoo Mail, so we do not recommend blocking these. However, you may wish to flag these for review the first time they attempt a transaction.
  • No MX records: This email address is registered to a domain name which has no MX records configured. This means it cannot receive email. We recommend blocking these.
  • No Gravatar: This email has no Gravatar attached to the email from which makes it slightly less likely to be a valid signup. This can be used for your own risk scoring or to trigger a manual review.

Email validation is configured by specifying the email types you wish to allow or deny, and whether you wish to modify certain validation options.

The arcjet client can be configured with one or more Email validation rules, which are constructed with the validateEmail(options: EmailOptions) function and configured by EmailOptions:

type EmailOptions =
| {
mode?: ArcjetMode | undefined;
allow: ArcjetEmailType[];
deny?: never | undefined;
requireTopLevelDomain?: boolean | undefined;
allowDomainLiteral?: boolean | undefined;
}
| {
mode?: ArcjetMode | undefined;
allow?: never | undefined;
deny: ArcjetEmailType[];
requireTopLevelDomain?: boolean | undefined;
allowDomainLiteral?: boolean | undefined;
};
type ArcjetMode = "LIVE" | "DRY_RUN";
type ArcjetEmailType =
"DISPOSABLE" | "FREE" | "NO_MX_RECORDS" | "NO_GRAVATAR" | "INVALID";

The allow and deny lists are mutually exclusive. With allow, Arcjet denies any email type that the list does not name. With deny, Arcjet allows any email type that the list does not name.

The validation options can usually be left as the defaults. However, if you wish to allow certain types of email addresses, you can modify the options:

  • requireTopLevelDomain: Whether or not to allow email addresses that don’t contain at least 2 domain segments (the domain name and TLD). Defaults to true. Changing to false means that foo@bar would be allowed.
  • allowDomainLiteral: Whether or not to allow email addresses with domain literals. Defaults to false. Changing to true means that foo@[123.456.789.0] would be allowed.

Arcjet provides a single protect function that is used to execute your protection rules. This requires a request argument which is the request context as passed to the request handler. When configured with a validateEmail rule it also requires an additional email prop.

This function returns a Promise that resolves to an ArcjetDecision object. This contains the following properties:

  • id (string) – The unique ID for the request. This can be used to look up the request in the Arcjet dashboard. It is prefixed with req_ for decisions involving the Arcjet cloud API. For decisions taken locally, the prefix is lreq_.
  • conclusion (ArcjetConclusion) – The final conclusion based on evaluating each of the configured rules. If you wish to accept Arcjet’s recommended action based on the configured rules then you can use this property.
  • reason (ArcjetReason) – An object containing more detailed information about the conclusion.
  • results (ArcjetRuleResult[]) – An array of ArcjetRuleResult objects containing the results of each rule that was executed.
  • ip (ArcjetIpDetails) – An object containing Arcjet’s analysis of the client IP address. For more information, see the SDK reference.

To check whether an email validation rule returned a deny conclusion, use decision.isDenied() and decision.reason.isEmail() (JS) / decision.is_denied() and decision.reason_v2.type == "EMAIL" (Python).

You can iterate through the results and check whether an email validation rule was applied:

for (const result of decision.results) {
console.log("Rule Result", result);
}

This example logs the full result as well as the email validation rule:

In addition to being able to deny specific email types, you can also configure Arcjet to only allow specific email types and Arcjet blocks all other types.

Arcjet returns the type of email address that it verified. This is one or several of the reported email types.

type ArcjetEmailType =
| "DISPOSABLE" // Disposable email address from a throwaway email service
| "FREE" // Email address from a free email service
| "NO_MX_RECORDS" // Email address with no MX records i.e. is undeliverable
| "NO_GRAVATAR" // Email address with no Gravatar profile
| "INVALID"; // Email address that is invalid

You can check the email type using the decision.reason.emailTypes (JS) / decision.reason_v2.email_types (Python) array:

let message = "";
// You could return specific messages based on the email type, but this would
// also reveal the validation to a spammer
if (decision.reason.emailTypes.includes("DISPOSABLE")) {
message = "We do not allow disposable email addresses.";
} else if (decision.reason.emailTypes.includes("FREE")) {
message =
"We do not allow free email addresses, please use a business address.";
} else if (decision.reason.emailTypes.includes("NO_MX_RECORDS")) {
message = "Your email domain does not have an MX record. Is there a typo?";
} else if (decision.reason.emailTypes.includes("NO_GRAVATAR")) {
message = "We require a Gravatar profile to sign up.";
} else {
// This is a catch all
message = "Invalid email.";
}

Arcjet is designed to fail open so that a service issue or misconfiguration does not block all requests. The SDK also times out and fails open after 1000 ms in development (see ARCJET_ENV) and 500 ms otherwise. However, in most cases, the response time is less than 20 ms to 30 ms.

If there is an error condition when processing the rule, Arcjet returns an ERROR result for that rule and you can check the message property on the rule’s error result for more information.

If all other rules that were run returned an ALLOW result, then the final Arcjet conclusion is ERROR.

Arcjet runs the same in any environment, including locally and in CI. You can use the mode set to DRY_RUN to log the results of rule execution without blocking any requests.

We have an example test framework you can use to automatically test your rules. Arcjet can also be triggered based using a sample of your traffic.

For details, see the Testing section of the docs.

The email validation stage considers the following RFCs:

  1. RFC 1123: Requirements for Internet Hosts — Application and Support, IETF, Oct 1989.
  2. RFC 3629: UTF-8, a transformation format of ISO 10646, IETF, Nov 2003.
  3. RFC 3696: Application Techniques for Checking and Transformation of Names, IETF, Feb 2004.
  4. RFC 4291: IP Version 6 Addressing Architecture, IETF, Feb 2006.
  5. RFC 5234: Augmented BNF for Syntax Specifications: ABNF, IETF, Jan 2008.
  6. RFC 5321: Simple Mail Transfer Protocol, IETF, Oct 2008.
  7. RFC 5322: Internet Message Format, I ETF, Oct 2008.
  8. RFC 5890: Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework, IETF, Aug 2010.
  9. RFC 6531: SMTP Extension for Internationalized Email, IETF, Feb 2012.
  10. RFC 6532: Internationalized Email Headers, IETF, Feb 2012.

Discussion