Validate Emails in React Native

Email address validation is a common operation for processing contact forms, sign-up forms, and so on. This exposes typos when a user enters his or her email address to register for your React Native app. Certainly, you can avoid tinkering with input validation and simply add a confirmation field. In this case, users will have to type their emails twice, and you won’t make it more of a problem for yourself than you have to. But, is this the way you really want to go about it? If it’s not, let’s learn about email validation in React Native apps. 

Email syntax validation vs. email address validation

The first thing we would like to mention is what email validation can refer to. In terms of this article (and most similar publications on the web), this term refers to the functionality that checks the syntax of input email addresses. Marketers, however, know email validation as a way to learn whether a specific email address is valid or not. For this, there are plenty of specialized tools like MyEmailVerifier or NeverBounce. We’ll touch upon this as well in the section APIs to check the validity of email addresses. Now, when we dispelled any possible misconceptions, let’s do the job. 

How to create your own email validation with a regular expression and why it’s a bad idea?

An email address consists of two parts – local and domain. The local part can contain alphanumeric characters, punctuation symbols, and special characters ($, %, etc.). At the same time, it cannot start and end with a full stop or dot. Also, the dot can’t be used consecutively like sam..williams@example.com. The domain part is based entirely on alphanumeric characters. Hyphens are also allowed if they are not the first or last character. Similarly to the dot, the hyphen cannot be used consecutively either. 

When you know the validation rules, you’ll be able to implement them in a regular expression or regex. That would be the best option for email validation. The thing is there is no universal validation regex. You can use an RFC 5322 compliant regex like: 

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?: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]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

Also, you can browse online and find some basic examples like:

  •  /\S+@\S+/ – checks whether the input email address consists of “something”, an @ symbol, and “something else”
  • or ^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$ – catches most valid email addresses.

Complicated and accurate regex are also available, but they might be too difficult to understand. For example, check out this advanced regex implemented via the validation function:

const validate = (email) => {
    const expression = /(?!.*\.{2})^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")@(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i;

    return expression.test(String(email).toLowerCase())
}

Some say that validating email addresses with regex is a waste of time. For example, jwz said:

“Some people, when confronted with a problem, think, ‘I know, I’ll use regular expressions.’ Now they have two problems”.

Whenever you try regex for validating emails, one day a user will come along and find his or her otherwise perfect email address invalid in your app. 

Email validation in React Native using JS libraries 

The cool thing about React Native is that you can choose from plenty of JavaScript libraries that have the validation logic already implemented. Here are the most worthwhile options:

Validate.js

We’ll start with Validate.js, a tool for email address validation. It provides a set of validators like URL, date, and so on. The email validator attempts to make sure the input is a valid email address. So, install the library first via npm install --save validate.js.

  • The first step is to set up constraints of the input fields. Create a constraints.js file and fill it with the following code:
export const constraints = {
  emailAddress: {
    presence: {
      allowEmpty: false,
      message: "^Please enter an email address"
    },
    email: {
      message: "^Please enter a valid email address"
    }
  },
};

export default constraints;

A caret ^ is responsible for skipping attribute name. Validators don’t include the argument name in the error message. We need an error not to be prefixed by the attribute, that’s why we added ^ to the error.

  • Next, we’ll work with the App.js file. Here we decided to nest all the form data in state under data to just pass to validate what is needed without additional flags.
import React, { Component } from 'react';
import { Text, View, TextInput, TouchableHighlight } from 'react-native';
import { validate } from 'validate.js';

import constraints from './constraints';

export default class MyForm extends Component {

  constructor(props) {
    super(props);
    this.state = { data: { emailAddress: "example@gmail.com" } };
    this._onPressButton = this._onPressButton.bind(this)
  }

  _onPressButton() {
    const validationResult = validate(this.state.data, constraints);
    // validationResult is undefined if there are no errors
    this.setState({ errors: validationResult });
  }

  render() {
      return (
        <View>
          <TextInput
            onChangeText={(email) => (
              this.setState({
                ...this.state,
                data: {
                  ...this.state.data,
                  emailAddress: email
                }
              })
            )}
            value={this.state.data.emailAddress}
          />

          <TouchableHighlight onPress={this._onPressButton}>
            <Text>Submit</Text>
          </TouchableHighlight>

          {this.isFieldInError('emailAddress') && this.getErrorsInField('emailAddress').map(errorMessage => <Text>{errorMessage}</Text>)}

          <Text>
            {this.getErrorMessages()}
          </Text>
        </View>
      );
  }

  getErrorMessages(separator="\n") {
    const { errors } = this.state;
    if (!errors) return [];

    return Object.values(errors).map(it => it.join(separator)).join(separator);
  }

  getErrorsInField(field) {
    const { errors } = this.state;
    return errors && errors[field] || [];
  }

  isFieldInError(field) {
    const { errors } = this.state;
    return errors && !!errors[field];
  }
}

Idiosyncrasy of Validate.js 

  • extensible and highly-customizable library for validating data against given schema defined as a list of validators per attribute
  • handles email syntax validation
  • UI is handled by ourselves, so can be creative 🙂

react-native-form-validator

Next is a simple library for input validation. react-native-form-validator lets you check the form field in your React Native app using the default or custom rules. Here is how it works (at the moment of writing, the version 0.2.0 was used):

  • Once you’ve installed the library using npm install 'react-native-form-validator' --save, extend the ValidationComponent class on the form component:
import React from 'react';
import { Text, View, TextInput, TouchableHighlight } from 'react-native';
import ValidationComponent from 'react-native-form-validator';

export default class MyForm extends ValidationComponent {
  • Then call the this.validate method upon form submission.
constructor(props) {
    super(props);
    this.state = { emailAddress: "example@gmail.com" };
    this._onPressButton = this._onPressButton.bind(this)
  }

  _onPressButton() {
    const isValid = this.validate({
      emailAddress: { email: true }
    });
validation errors
    this.setState({ isValid });
  }

The arguments should represent the React component state. { email: true } describes the validation rules (default rules can be found in the defaultRules.js file). For example, a default rule for email is

/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

If you want to use your own rules, add the React props component

const rules = {any: /^(.*)$/};

<MyForm rules={rules} />

They will override defaultRules.js

  • Default error labels for input fields are available in the defaultMessages.js file. If you want to make custom ones, use the React props component:
const messages = {
  en: {email: "The email address is not valid"},
};

<MyForm messages={messages} />

It is also possible to specify a default custom language:

<MyForm deviceLocale="es" />

Check out the full code example to see the library in action:

import React from 'react';
import { Text, View, TextInput, TouchableHighlight } from 'react-native';
import ValidationComponent from 'react-native-form-validator';

export default class MyForm extends ValidationComponent {

  constructor(props) {
    super(props);
    this.state = { emailAddress: "example@gmail.com" };
    this._onPressButton = this._onPressButton.bind(this)
  }

  _onPressButton() {

    const isValid = this.validate({
      emailAddress: { email: true }
    });

    this.setState({ isValid });
  }

  render() {
      return (
        <View>
          <TextInput onChangeText={(email) => this.setState({ emailAddress: email })} value={this.state.emailAddress} />

          <TouchableHighlight onPress={this._onPressButton}>
            <Text>Submit</Text>
          </TouchableHighlight>

          {this.isFieldInError('emailAddress') && this.getErrorsInField('emailAddress').map(errorMessage => <Text>{errorMessage}</Text>) }

          <Text>
            {this.getErrorMessages()}
          </Text>
        </View>
      );
  }
}

Idiosyncrasy of react-native-form-validator

  • iterates over entire component state for data
  • handles collecting and providing error messages based on a given schema and data (taking directly from component’s state)
  • handles email syntax validation
  • form fields, labels, placeholders, error messages are rendered explicitly by own code
  • UI is handled by ourselves, so can be creative 🙂

tcomb-form-native + email-validator

tcomb-form-native is a rather popular library to validate forms in React Native. email-validator is a simple module that checks form, not function. If used together, they are the most complete solution for rendering forms based on types for validations. Check out this working code sample with tcomb-form-native and email-validator:

import React, { Component, createRef } from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import t from 'tcomb-form-native';
import { validate as validateEmail } from 'email-validator';

const Form = t.form.Form;

const Email = t.refinement(t.String, validateEmail)

const Login = t.struct({
  emailAddress: Email
});

const options = {
  fields: {
    emailAddress: {
      error: 'Please enter a valid email address'
    }
  },
  order: ['emailAddress']
}

export default class MyForm extends Component {

  constructor(props) {
    super(props);
    this.state = { emailAddress: "example@gmail.com" };
    this._onPressButton = this._onPressButton.bind(this);
    this.formRef = createRef();
  }

  _onPressButton() {
    const value = this.formRef.current.getValue();
    if (value) { // if validation fails, value will be null

    }
  }

  render() {
    return (
      <View>
        <Form ref={this.formRef} type={Login} value={this.state} options={options} />
        <TouchableHighlight onPress={this._onPressButton}>
          <Text>Submit</Text>
        </TouchableHighlight>
      </View>
    )
  }
}

Idiosyncrasy of tcomb-form-native + email-validator

  • implicitly renders entire form for given schema (based on types) and data; it can be tailored
  • validates data on demand when `validate` or `getValue` are called
  • lacks email validation so taken from email-validator
  • gives a head start with default styling, but might be more cumbersome to fully tailor UI to one’s needs

APIs to check the validity of email addresses

One job is done – you have implemented the email syntax validity in your React Native app. But still, this won’t prevent you from users who sign up using disposable email addresses. So what? Temporary email services like Nada can be used as a bypass to abuse freemium features. Also, if your email campaign will contain many disposable recipients, your sender reputation will go down. As a result, spam filters will be at odds with the messages sent from your domain. Wouldn’t it be awesome if your app could detect such dodgers and encourage them to sign up with their personal or business email addresses? The following services provide a solution. Their APIs can be easily integrated into your app and will close the door on fake users.

Byteplant’s Email Validator

Byteplant allows you to check the quality of email addresses right at the point of sign-up. Email Validator API detects if the input address is valid. So, you’ll be able to filter disposable and fake input data. Email syntax validation is also supported.

Mailgun

Mailgun is a popular email service for developers. Its API provides a three-step validation check and a comprehensive email verification. Also, it catches user-entry errors in your sign-up flow.

Trumail

Trumail offers an accurate email validation API written in Go. It allows you to make an instant informed decision on user validity. Soon, the tool will release an opportunity for bulk lookups as well.

How can I check the email sending capability of my React Native app?

Let’s say, you’ve successfully implemented email validation for the sign-up form in your app. The next step is to send a confirmation message to the input email address. For more on this, read the blog post about sending emails in React Native. And what if this transactional email ends up in the spam or doesn’t even hit the recipient’s mailbox? You can prevent such a fiasco if you test your React Native app using a fake SMTP server in advance. That’s how it looks through the example of Mailtrap:

  • You tweak your app code with the credentials of a fake SMTP server. 
  • You send the email from your React Native app to any real or made-up email address 
  • You check your Demo inbox and see how your email will look in the recipient’s inbox

Of course, you can do testing with the real SMTP server and a real email address. But the server can fail to function or respond negatively to the client command. And it’s unlikely you’ll want to spam real users with testing emails. Anyway, it’s up to you. 

We hope that our blog post will help you propel your project’s email validation feature. Perhaps you have other challenges related to web or mobile app development? Check out our blog – it contains answers to several questions you might have. Good luck!