Node.js Email Validation: How I Validate Emails Step-by-Step

On April 29, 2024
7min read
Yevhenii Odyntsov Content @Mailtrap

In this article, I aim to make Node.js email validation easy for you by describing the process step by step.

To freshen up or fine-tune your knowledge, check out my dedicated article on email validation.

Validate emails with the Deep email validator module

Now, let me show you how I validate emails with Deep email validator, an MIT-certified dependency package that uses several different checks to make sure an email address is valid. Namely, the package validates:

  • RegEx – Makes sure the email format conforms to standard email patterns (e.g., has an ‘@’ next to ‘.’)
  • Common typos – Uses mailcheck to validate common typos such as example@gamil.com.
  • Disposable email blacklists –  Identifies temporary addresses from known disposable email address providers.
  • DNS records – Ensures the domain has valid MX records.
  • SMTP server response – Checks whether the SMTP server is running and whether the mailbox exists on it.

To install the Deep email validator, I typically use the npm command:

npm i deep-email-validator --save

But, you can also do it with yarn:

yarn add deep-email-validator

Then, in my /register controller I add a code that goes something like this:

const express = require('express');
const mongoose = require('mongoose');
const { validate } = require('deep-email-validator');


// Connect to MongoDB
// Replace 'your-connection-string-here' with your actual MongoDB connection string
const uri = 'your-connection-string-here';
mongoose.connect(uri)
   .then(() => console.log('MongoDB connected'))
   .catch((err) => console.error('Error connecting to MongoDB', err));


// Define the User model
const userSchema = new mongoose.Schema({
   email: { type: String, required: true, unique: true },
   password: { type: String, required: true }
});
const User = mongoose.model('User', userSchema);


const app = express();
app.use(express.json());


// register route
app.post('/register', async (req, res) => {
   const { email, password, passwordverify } = req.body;


   // Validate the email
   const validationResult = await validate(email);


   if (!validationResult.valid) {
       return res.status(400).send({
           status: 'error',
           message: 'Email is not valid. Please try again!',
           reason: validationResult.reason
       });
   }


   // Validate password similarity
   if (password !== passwordverify) {
       return res.status(400).json({
           status: 'error',
           message: 'Passwords do not match'
       });
   }


   try {
       // Check if user already exists
       const foundUser = await User.findOne({ email });
       if (foundUser) {
           return res.status(409).json({
               status: 'error',
               message: 'Already a user! Please login to your account'
           });
       }


       // Create new user
       // please note that we shouldn't store plain passwords in a database
       // it should first be hashes, but we keep it simple for the demo
       const newUser = new User({ email, password });
       await newUser.save();
       res.status(201).json({
           status: 'success',
           message: 'User registered successfully'
       });
   } catch (err) {
       res.status(500).json({
           status: 'error',
           message: 'Database error: ' + err.message
       });
   }
});


// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`));

This uses async/await syntax and validates email addresses before even looking into the database.

For more options and settings, be sure to check out the official GitHub page.

Other packages you can use for Node.js email validation

Deep email validator isn’t the only module for validating emails in Node.js. It’s just a module that, in my opinion, is the most efficient due to the number of checks it performs.

There’s a bunch of other packages you can use, some of which include:

  • validator – Another MIT-licensed package that offers an API for email validation. It can be heavily customized but note that it’s geared towards advanced users.
  • email-validator – Super easy to use, performs basic checks, making it perfect for people who are looking for a simple validation solution.
  • node-email validation – Another straightforward email validator that even has a demo page. Additionally, it also has an MIT License.
  • email-existence – This email validator makes sure email addresses exist by performing real-time checks on the SMTP server.
  • valid-email – An easy choice if you’re looking for a package that checks for typos and address formats.

Pro tips

  • When choosing a package, be sure to consider the level of email validation your application needs, how easy to use it is, and whether it’s regularly updated and maintained.
  • To check whether a package you’re interested in is still regularly updated and maintained, or whether it has certain security issues, I personally use Snyk.

Node.js regular expressions for email validation

Think your app doesn’t need a dependency package for comprehensive validation? If so, you can run basic ReGex checks against the email IDs by simply pasting the following code snippet into your project file (e.g., app.js):

const emailRegex = 

/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/


function isEmailValid(email) {
    // Check if the email is defined and not too long
    if (!email || email.length > 254) return false;

    // Use a single regex check for the standard email parts
    if (!emailRegex.test(email)) return false;

    // Split once and perform length checks on the parts
    const parts = email.split("@");
    if (parts[0].length > 64) return false;

    // Perform length checks on domain parts
    const domainParts = parts[1].split(".");
    if (domainParts.some(part => part.length > 63)) return false;

    // If all checks pass, the email is valid
    return true;
}

Additionally, in the same project file, below the RegEx code, you can also add a route for email validation, like so:

app.post('/validate-email', (req, res) => {
    try {
        const { email } = req.body;
        if (isEmailValid(email)) {
            res.status(200).send({ message: "Email is valid" });
        } else {
            res.status(400).send({ message: "Email is not valid" });
        }
    } catch (error) {
        res.status(500).send({ message: "Server error" });
    }
});

Bonus section: email verification in Node.js

Email validation is a procedure that helps identify whether an email has typos or not. 

In Node.js, you can validate emails either with validator modules (packages) or regular expressions (RegEx). Modules are a more robust solution with comprehensive validation, whereas RegEx provides a straightforward method and simply matches strings against a specified pattern.

Keep in mind that validation is often misused with email verification. However, verification not only checks whether an email has typos, but it also ensures that someone is actually behind that address by sending an activation link/code the end user activates from their inbox.

Here’s my flow for email verification in Node.js:

1. Setup your Node.js project

First, create a new directory for your project and initialize a new Node.js project within it by running [npm init], which will set up your package.json file.

Then, install the required packages:

  • jsonwebtoken for generating tokens;
  • express for setting up the server;
  • nodemailer for sending emails;
npm install jsonwebtoken express nodemailer

We’ll also need basic files, such as:

  • app.js – The main server file.
  • tokenSender.js – Although often included in app.js in simple setups, we’ll use this file to handle the token generation and email-sending logic.

2. Generate tokens and send an email

After setting up your Node.js project, let’s generate a token with jwt and send an email with Nodemailer, like so:

const nodemailer = require('nodemailer'); 
const jwt = require('jsonwebtoken'); 

const transporter = nodemailer.createTransport({ 
	host: secure_configuration.HOST,
            port: secure_configuration.PORT,
	auth: { 
		user: secure_configuration.EMAIL_USERNAME, 
		pass: secure_configuration.PASSWORD 
	} 
}); 

const token = jwt.sign({ 
		data: 'Token Data' . 
	}, 'ourSecretKey', { expiresIn: '10m' } 
);	 

const mailConfigurations = { 

	// It should be a string of sender/server email 
	from: 'ivan.djuric@railsware.com', 

	to: 'djuric.eth@gmail.com', 

	// Subject of Email 
	subject: 'Email Verification', 
	
	// This would be the text of email body 
	text: `Hi there, you have recently entered your 
		email on our website. 

		Please follow the given link to verify your email 
		http://localhost:3000/verify/${token} 

		Thanks` 
	
}; 

transporter.sendMail(mailConfigurations, function(error, info){ 
	if (error) throw Error(error); 
	console.log('Email Sent Successfully'); 
	console.log(info); 
});

Notes:

  • I imported the nodemailer package in the first line, which will be used for sending emails later on.
  • I also created a transporter object for sending email with some basic configuration regarding the email service and sender.
    • As you can see, for my email service, I use Mailtrap Email Sending, which offers robust email-sending capabilities. However, feel free to use a different service like your Gmail account, but keep in mind it has some limitations, especially for production environments.
  • Lastly, I added another object with information about the receiver, sender, email text, etc.

3. Create a route to verify the token

And finally, let’s set up an Express server and create a route that listens for GET requests. What this route does is it extracts the token from the URL, verifies it using jsonwebtoken, and responds accordingly. Check it out:

const express = require('express'); 
const jwt = require('jsonwebtoken'); 

const app = express(); 
const PORT = 3000; 

app.get('/verify/:token', (req, res)=>{ 
	const {token} = req.params; 

	// Verifying the JWT token 
	jwt.verify(token, 'ourSecretKey', function(err, decoded) { 
		if (err) { 
			console.log(err); 
			res.status(400).json({ error: "Email verification failed, possibly the link is     invalid or expired" });
		} 
		else { 
			res.status(200).json({ message: "Email verified successfully"});
		} 
	}); 
}); 

app.listen(PORT, (error) =>{ 
	if(!error) 
		console.log("Server is Successfully Running, 
				and App is listening on port "+ PORT) 
	else
		console.error("Error occurred, server can't start", error);
	} 
); 

To run the server, you can use the node command node app.js.

If you’ve followed everything correctly, you should receive your test email in the inbox. By clicking on the link in the message, you’ll make a request on the server and it will respond accordingly as email is verified.

Pro tips

  • Implement rate limiting to prevent abuse of the verification process with a package like express-rate-limit.
  • Set up token expiration links so they can’t be used indefinitely, which is a common security practice for authentication, password resets, and email verification. To generate a token with an expiration time, you can use the following code:
const jwt = require('jsonwebtoken');

const token = jwt.sign({
    data: 'your-data' // your payload here
}, 'yourSecretKey', { expiresIn: '1h' }); // Token expires in one hour

Email validation and verification in email testing

Both validation and verification increase your email deliverability by helping you keep your email lists spotless

But, even if all your addresses are valid and have users behind them, sending your emails without testing them beforehand can significantly decrease your odds of reaching recipients’ inboxes.

That’s why I recommend you first test your emails, make sure they’re pitch-perfect, and only then send them out.

For this, I use Mailtrap Email Testing, which is another inseparable part of Mailtrap Email Delivery Platform.

With Mailtrap Email Testing, you can catch traffic from staging and dev environments and analyze their HTML/CSS. This way, you can fix or remove any faulty lines of code before sending out your emails, ensuring they’re flawless before they land in your recipients’ inboxes.

You can also check your spam score with the Spam Analysis feature. And if you keep this score under 5, you proactively solve a considerable number of potential email deliverability issues once your app moves to production.

Moreover, you can design, edit, and test, your HTML email templates and then easily switch to the production environment when you’re ready to start sending, which can come in handy if you decide to implement email verification.

Last but not least, besides these and other advanced features, Mailtrap Email Testing is also super easy to configure and use. Check it out!

Article by Yevhenii Odyntsov Content @Mailtrap

I’ve been writing email-oriented content for over 4 years now and I’m still finding new and exciting topics and technologies about email infrastructure and deliverability, email sending and testing, and much more. I hope you’ll enjoy it!