User registration is a core feature of most modern applications. But registration alone is not enough. To avoid fake accounts, spam, and unauthorized access, applications must verify user email addresses before allowing access to protected features. Email verification adds a strong security layer and improves user trust in your system.
In this article, you will learn how to build a complete Email Verification System using:
This tutorial uses simple language, clear structure, and practical code so beginners and professionals can implement it easily.
What You Will Build
By the end of this tutorial, you will have:
A registration system that sends a verification email
A unique verification token stored in the database
A verification URL sent to the user
An API endpoint to verify the email
Angular pages for registration and email confirmation
A secure flow that ensures the user cannot log in unless verified
This is the same pattern used by most professional systems such as Google, Microsoft, Amazon, and major SaaS platforms.
Why Email Verification Matters
Email verification protects the system from:
It ensures the email belongs to the user who signed up.
System Architecture Overview
The verification system works like this:
User registers in Angular
Backend creates a user record in SQL
Backend generates a unique verification token
Token saved to database
Email sent to user with verification link
User clicks verification link
Backend confirms the token
User is marked as EmailVerified = true
User can now log in
This is a secure and scalable method used in industry.
Part 1: Backend Iplementation (ASP.NET Core)
Step 1: Update User Model
File: Models/User.cs
public class User
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
public bool EmailVerified { get; set; } = false;
public string VerificationToken { get; set; }
public DateTime? VerifiedAt { get; set; }
}
We added:
EmailVerified
VerificationToken
VerifiedAt
Step 2: Generate Verification Token
Create a helper:
public static class TokenGenerator
{
public static string GenerateToken()
{
return Convert.ToHexString(RandomNumberGenerator.GetBytes(32));
}
}
Step 3: Modify Registration Endpoint
When user registers:
[HttpPost("register")]
public async Task<IActionResult> Register(UserDto request)
{
if (_context.Users.Any(u => u.Email == request.Email))
return BadRequest(new { Message = "Email already exists" });
var user = new User
{
FullName = request.FullName,
Email = request.Email,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
VerificationToken = TokenGenerator.GenerateToken()
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
await _emailService.SendVerificationEmail(user.Email, user.VerificationToken);
return Ok(new { Message = "Registration successful. Please check your email to verify your account." });
}
Step 4: Configure Email Sending (SMTP)
Create Services/EmailService.cs
using System.Net;
using System.Net.Mail;
public class EmailService
{
private readonly IConfiguration _config;
public EmailService(IConfiguration config)
{
_config = config;
}
public async Task SendVerificationEmail(string email, string token)
{
var verifyUrl = $"{_config["App:BaseUrl"]}/verify-email?token={token}";
var message = new MailMessage();
message.From = new MailAddress(_config["Email:From"]);
message.To.Add(email);
message.Subject = "Verify Your Email";
message.Body = $"Click the link to verify your email: {verifyUrl}";
using var smtp = new SmtpClient(_config["Email:SmtpServer"])
{
Port = int.Parse(_config["Email:Port"]),
Credentials = new NetworkCredential(
_config["Email:Username"],
_config["Email:Password"]
),
EnableSsl = true
};
await smtp.SendMailAsync(message);
}
}
Add to Program.cs:
builder.Services.AddScoped<EmailService>();
Step 5: Add Email Settings in appsettings.json
"Email": {
"From": "[email protected]",
"SmtpServer": "smtp.gmail.com",
"Port": "587",
"Username": "[email protected]",
"Password": "your-email-password"
},
"App": {
"BaseUrl": "http://localhost:4200"
}
Step 6: Create Verify Email API Endpoint
File: AuthController.cs
[HttpGet("verify-email")]
public async Task<IActionResult> VerifyEmail(string token)
{
var user = await _context.Users.FirstOrDefaultAsync(u => u.VerificationToken == token);
if (user == null)
return BadRequest(new { Message = "Invalid token" });
user.EmailVerified = true;
user.VerifiedAt = DateTime.Now;
await _context.SaveChangesAsync();
return Ok(new { Message = "Email verified successfully" });
}
Step 7: Block Login if Email Not Verified
Modify Login endpoint:
if (!user.EmailVerified)
return BadRequest(new { Message = "Email not verified. Please check your inbox." });
Backend is now ready.
Part 2: Frontend Implementation (Angular)
Step 1: Update Register Component
After registration, show a message:
this.auth.register(this.model).subscribe({
next: (res: any) => {
this.message = "Registered successfully. Check your email to verify your account.";
}
});
Step 2: Create VerifyEmail Component
ng generate component verify-email
verify-email.component.ts
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
@Component({
templateUrl: './verify-email.component.html'
})
export class VerifyEmailComponent {
message = "";
constructor(private route: ActivatedRoute, private http: HttpClient) {}
ngOnInit() {
const token = this.route.snapshot.queryParams["token"];
this.http.get("https://localhost:5001/api/auth/verify-email?token=" + token)
.subscribe({
next: (res: any) => this.message = res.message,
error: () => this.message = "Verification failed"
});
}
}
verify-email.component.html
<h2>Email Verification</h2>
<p>{{ message }}</p>
Step 3: Add Route
app-routing.module.ts
{ path: 'verify-email', component: VerifyEmailComponent }
Step 4: Modify Login Component
When email is not verified:
error: err => {
this.message = err.error.message;
}
Part 3: Full Verification flow
User registers
Backend creates a verification token
Email with verification link is sent
User clicks the link
Backend verifies the token
User marked as verified
User can now log in
Angular prevents login until verification is complete
This ensures only real users access your system.
Part 4: Bonus Improvements
You can enhance the system with:
Token expiration for verification links
Resend verification email
Verification email templates (HTML templates)
Tracking verification attempts
Logging email delivery
Adding CAPTCHA to registration
Temporary user accounts before verification
If you need any of these, I can write a full article.
Conclusion
In this article, you learned how to create a complete Email Verification System using ASP.NET Core, SQL Server, and Angular. The system includes:
Secure registration
Token-based verification
Email sending via SMTP
Protected login until verification
Angular verification page
Database tracking of verified users
This is a professional and secure approach used in production applications.