Email verification has become a standard feature in modern web applications. Whether you're building an e-commerce platform, a social media application, or a job portal, verifying a user's email helps ensure that accounts belong to real users while reducing spam and fake registrations.
During one of my MERN stack projects, I wanted to implement email-based OTP verification. Initially, I had no idea where to start. I knew the feature was important, but I wasn't sure how production applications handled it. So, I spent time researching different approaches, reading documentation, and even asking AI how large companies implement email verification systems.
This article summarizes what I learned and explains the approach I found easiest to implement.
Different Ways to Send OTP Emails
There are several ways to send verification emails from your application.
1. Nodemailer (The Simplest for MERN Applications)
If you're using Node.js, Nodemailer is one of the easiest libraries to integrate. It allows your backend to send emails through providers like Gmail, Outlook, or SMTP servers with very little setup.
For personal projects, learning, or small-scale applications, this is an excellent choice because it requires minimal configuration.
2. Email Service Providers (Recommended for Production)
As I researched further, I found that most large companies don't send emails directly using Gmail. Instead, they use dedicated email delivery services such as:
- Amazon SES
- SendGrid
- Mailgun
- Postmark
- Brevo (formerly Sendinblue)
These services provide:
- Better email deliverability
- Higher sending limits
- Analytics
- Bounce handling
- Spam protection
- Improved reliability
Many of these services also provide Node.js SDKs, making integration straightforward.
3. SMTP Servers
Another option is connecting your application directly to an SMTP server. Many hosting providers and organizations provide SMTP credentials that applications can use to send emails.
This approach offers more control but usually requires additional configuration.
Why I Chose Nodemailer
Since my project was built using the MERN stack, I found Nodemailer to be the simplest solution.
It integrates seamlessly with Express.js and only requires a few lines of code to send emails. The extensive documentation and large community also make troubleshooting much easier.
For learning purposes and personal projects, I believe this is one of the best ways to understand how email verification works before moving on to enterprise-grade services.
Creating a Google Account and Getting Credentials
To use Gmail with Nodemailer, you'll first need a Google account.
Instead of using your normal Gmail password, Google recommends creating an App Password.
The general process is:
- Create or use an existing Google account.
- Enable 2-Step Verification on the account.
- Navigate to your Google Account security settings.
- Generate an App Password.
- Use the generated email address and App Password inside your Node.js application.
These credentials allow Nodemailer to securely authenticate with Gmail without exposing your actual account password.
Database Design
While designing the User model, I added a simple field:
isEmailVerified: {
type: Boolean,
default: false
}
This field determines whether the user has successfully verified their email address.
Whenever a new account is created, this value remains false until the OTP verification process is completed.
Login Flow
One thing I wanted to avoid was allowing unverified users to access the application.
The login flow works like this:
- User enters email and password.
- Validate the credentials.
- Check the
isEmailVerifiedfield. - If the value is
true, allow login. - If the value is
false, redirect the user to the OTP verification page.
On the OTP page, the user's email is already pre-filled, making the process faster and more user-friendly.
Sending the OTP
When the user clicks the Send OTP button:
- Generate a random 6-digit OTP.
- Set an expiration time (typically 5–10 minutes).
- Send the OTP to the registered email using Nodemailer.
This creates a smooth experience while preventing unnecessary emails from being sent automatically.
Never Store OTPs in Plain Text
One important lesson I learned is that OTPs should never be stored directly in the database.
Instead:
- Hash the OTP using a secure hashing algorithm such as bcrypt.
- Store only the hashed version.
- Keep an expiration timestamp.
- Delete or invalidate the OTP after successful verification or expiry.
This ensures that even if someone gains database access, they cannot view users' OTPs.
Verifying the OTP
Once the user enters the OTP:
- Retrieve the stored hashed OTP.
- Compare the entered OTP with the hashed value.
- Verify that the OTP hasn't expired.
- If the OTP matches:
- Update
isEmailVerifiedtotrue. - Remove the stored OTP.
- Allow the user to continue using the application.
- Update
- If the OTP is incorrect or expired, ask the user to request a new OTP.
Additional Best Practices
While implementing the feature, I also discovered several practices commonly used in production applications:
- Limit the number of OTP requests within a certain time window.
- Add a cooldown (for example, 30–60 seconds) before allowing another OTP request.
- Set OTP expiration to 5–10 minutes.
- Limit incorrect verification attempts.
- Log verification events for auditing.
- Use HTTPS to protect data during transmission.
- Prevent brute-force attacks with rate limiting.
These measures improve both security and user experience.
What I Learned
Before implementing this feature, I assumed email verification would be difficult. After researching multiple approaches, I realized the overall concept is actually straightforward once you understand the authentication flow.
For my MERN stack application, Nodemailer turned out to be the easiest solution because it integrates naturally with Node.js and Express. Later, I also learned that larger companies usually rely on dedicated email services like Amazon SES or SendGrid for better scalability and reliability.
If you're building your first full-stack application, implementing email OTP verification is a great way to strengthen your understanding of authentication, backend development, database design, and application security. Once you understand the fundamentals, transitioning to enterprise-grade email providers becomes much easier.
Top comments (0)