Skip to content

Email validation reference

Arcjet allows you validate & 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.

Plan availability

Arcjet email validation availability depends depends on your pricing plan.

PlanEmail validation
Free No
Pro Yes
Enterprise Custom

Configuration

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[];
block?: never | undefined;
deny?: never | undefined;
requireTopLevelDomain?: boolean | undefined;
allowDomainLiteral?: boolean | undefined;
}
| {
mode?: ArcjetMode | undefined;
allow?: never | undefined;
block?: never | undefined;
deny: ArcjetEmailType[];
requireTopLevelDomain?: boolean | undefined;
allowDomainLiteral?: boolean | undefined;
}
| {
mode?: ArcjetMode | undefined;
allow?: never | undefined;
block: ArcjetEmailType[];
deny?: never | undefined;
requireTopLevelDomain?: boolean | undefined;
allowDomainLiteral?: boolean | undefined;
};
type ArcjetMode = "LIVE" | "DRY_RUN";
type ArcjetEmailType =
| "DISPOSABLE"
| "FREE"
| "NO_MX_RECORDS"
| "NO_GRAVATAR"
| "INVALID";

The allowand deny lists are mutually-exclusive, such that using allow will result in a DENY decision for any email type that is not specified in the allow list and using deny will result in an ALLOW decision for any email type that is not specified in the deny list.

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.

Decision

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. See the SDK reference for more information.

You check if a deny conclusion has been returned by an email validation rule by using decision.isDenied() and decision.reason.isEmail().

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 will log the full result as well as the email validation rule:

Allowing specific email types

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

Checking the email type

Arcjet will return the type of email address that was verified. This will be one or several of the reported email types.

// See https://docs.arcjet.com/email-validation/concepts#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 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.";
}

Error handling

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

If there is an error condition when processing the rule, Arcjet will return 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 will be ERROR.

Testing

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.

See the Testing section of the docs for details.

Discussion