ASP.NET Core  

Building an Email Verification System with HTML Templates in ASP.NET Core and Angular

A Complete Step-by-Step Tutorial for Beginners

Email verification is an essential step in modern applications. It ensures that users provide valid email addresses, reduces spam registrations, and improves security. While sending plain text emails is simple, using HTML email templates enhances user experience by allowing styled content, logos, buttons, and better formatting.

In this tutorial, we will create a full email verification system using:

  • ASP.NET Core Web API

  • SQL Server

  • Angular Frontend (optional for verification page)

  • HTML email templates

  • Token-based email verification workflow

We will explain each step clearly with practical examples.

What You Will Build

  1. User registration system

  2. Backend generates a unique verification token

  3. Email is sent using HTML templates with a verification link

  4. User clicks the verification link

  5. Backend verifies the token and marks the user as verified

  6. Angular frontend displays success or error message

This workflow is professional and used in production applications like Gmail, Microsoft, and online banking.

Why HTML Email Templates Are Important

Using HTML templates allows:

  • Rich content like logos, buttons, and colors

  • Clear call-to-action for verification

  • Better mobile compatibility

  • Branding consistency

  • Improved user engagement

Part 1: Backend Implementation (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; }
}

Step 2: Generate Verification Token

Create a helper class:

using System.Security.Cryptography;

public static class TokenGenerator
{
    public static string GenerateToken()
    {
        return Convert.ToHexString(RandomNumberGenerator.GetBytes(32));
    }
}

Step 3: Create Email Service Using HTML Templates

Install MailKit and MimeKit for sending HTML emails:

dotnet add package MailKit

File: Services/EmailService.cs

using MailKit.Net.Smtp;
using MimeKit;

public class EmailService
{
    private readonly IConfiguration _config;

    public EmailService(IConfiguration config)
    {
        _config = config;
    }

    public async Task SendVerificationEmail(string toEmail, string userName, string token)
    {
        var verifyUrl = $"{_config["App:BaseUrl"]}/verify-email?token={token}";

        // Load HTML template
        var template = File.ReadAllText("EmailTemplates/VerifyEmailTemplate.html");
        template = template.Replace("{{UserName}}", userName)
                           .Replace("{{VerifyUrl}}", verifyUrl);

        var email = new MimeMessage();
        email.From.Add(MailboxAddress.Parse(_config["Email:From"]));
        email.To.Add(MailboxAddress.Parse(toEmail));
        email.Subject = "Verify Your Email";

        var bodyBuilder = new BodyBuilder
        {
            HtmlBody = template
        };
        email.Body = bodyBuilder.ToMessageBody();

        using var smtp = new SmtpClient();
        await smtp.ConnectAsync(_config["Email:SmtpServer"], int.Parse(_config["Email:Port"]), true);
        await smtp.AuthenticateAsync(_config["Email:Username"], _config["Email:Password"]);
        await smtp.SendAsync(email);
        await smtp.DisconnectAsync(true);
    }
}

Step 4: Create HTML Template

Folder: EmailTemplates/VerifyEmailTemplate.html

<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial, sans-serif; background-color: #f5f5f5; }
        .container { max-width: 600px; margin: auto; background: white; padding: 20px; border-radius: 5px; }
        .button { background-color: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px; }
        .footer { margin-top: 20px; font-size: 12px; color: #888; }
    </style>
</head>
<body>
    <div class="container">
        <h2>Hello {{UserName}},</h2>
        <p>Thank you for registering. Please click the button below to verify your email address:</p>
        <p><a href="{{VerifyUrl}}" class="button">Verify Email</a></p>
        <p>If you did not register, please ignore this email.</p>
        <div class="footer">
            &copy; 2025 MyApp. All rights reserved.
        </div>
    </div>
</body>
</html>

Step 5: Registration Endpoint

AuthController.cs

[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.FullName, user.VerificationToken);

    return Ok(new { Message = "Registration successful. Please check your email to verify your account." });
}

Step 6: Verify Email Endpoint

[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;
    user.VerificationToken = null;
    await _context.SaveChangesAsync();

    return Ok(new { Message = "Email verified successfully." });
}

Part 2: Frontend Implementation (Angular)

Angular is optional but recommended for user-friendly verification pages.

Step 1: Create VerifyEmail Component

ng generate component verify-email

verify-email.component.ts

import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';

@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>
<a routerLink="/login">Go to Login</a>

Step 2: Add Route

app-routing.module.ts

{ path: 'verify-email', component: VerifyEmailComponent }

Part 3: Configuration

appsettings.json

"Email": {
  "From": "[email protected]",
  "SmtpServer": "smtp.gmail.com",
  "Port": "587",
  "Username": "[email protected]",
  "Password": "your-email-password"
},
"App": {
  "BaseUrl": "http://localhost:4200"
}
  • BaseUrl should match the Angular app URL

  • SMTP settings depend on your provider

Part 4: Testing the system

  1. Register a new user → check email inbox

  2. Click verification link → Angular page displays success

  3. Attempt login before verification → backend should prevent login

  4. Attempt login after verification → login succeeds

Part 5: Optional Enhancements

  • Add token expiration for verification links

  • Send resend verification email feature

  • Use dynamic HTML templates with Razor or Liquid

  • Add email tracking (opened, clicked)

  • Style emails for mobile responsiveness

  • Include company branding and logos

Conclusion

You now have a complete Email Verification System with HTML templates using:

  • ASP.NET Core Web API

  • SQL Server

  • Angular frontend

  • Token-based verification

  • Styled HTML email templates

This approach ensures professional, secure, and user-friendly registration workflows suitable for production applications.