How to integrate email confirmation of user accounts in an ASP.NET core MVC and Entity Framework web app?

Hamza Abbasi 1 Reputation point
2022-11-17T15:28:10.587+00:00

0

I am new to web app development and recently used ASP.NET Core 3.1 MVC and Entity Framework in Visual Studio 2019 to create a web app using the individual accounts authentication.

Currently, I have the website setup in which when a new user registers, the confirmation email could be done right away on the website by clicking one of the generated links by default.

What my goal is, to send this confirmation link to the user email for the confirmation process.

Any leads or the resources that I could follow to achieve this would be appreciated!

I have already tried few of the tutorials, some of them used the account controller to integrate this feature which I don't have in my project structure. I only have one default HomeController in my project.

Few tutorials add some classes in the services folder, which also I don't have in my project directory.

I have already scaffolded the Register.cshtml and Login.cshtml and they're now available in the Areas/Identity folder.

Many thanks!

Entity Framework Core
Entity Framework Core
A lightweight, extensible, open-source, and cross-platform version of the Entity Framework data access technology.
689 questions
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,077 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Xinran Shen - MSFT 2,091 Reputation points
    2022-11-18T06:32:51.617+00:00

    Hi @Hamza Abbasi ,
    From your description of the question, I think you have scaffolded identity code and you don't want to create a controller to send email.
    You can create a service to send email and inject this service into Register.cshtml.cs.

    First, You need to scaffolded Account.RegisterConfirmation .

    Here I'm using Mailkit to send email, You can also use another email provider.

    Installing NuGet package MailKit  
    

    Create a service to send email:

    public class SendEmail  
        {  
            public void send(string UserName,string body)  
            {  
                var email = new MimeMessage();  
                email.From.Add(MailboxAddress.Parse("EmailName"));  
                email.To.Add(MailboxAddress.Parse(UserName));  
                email.Subject = "Confirm your account";  
                email.Body = new TextPart(MimeKit.Text.TextFormat.Html) {Text = body };  
      
                using var smtp = new SmtpClient();  
      
                //Here i'm using smtp.ethereal to test, you can also use another SMTP server provides.  
                smtp.Connect("smtp.ethereal.email", 587, MailKit.Security.SecureSocketOptions.StartTls);  
                smtp.Authenticate("EmailName", "Password");  
                smtp.Send(email);  
                smtp.Disconnect(true);  
            }  
        }  
    

    Then register this server in your startup.cs

    services.AddScoped<SendEmail>();  
    

    You need to inject SendEmail into your Register.cshtml.cs and change some code:

    public class RegisterModel : PageModel  
        {  
           //.........  
            private readonly SendEmail _sendEmail;  
      
            public RegisterModel(SendEmail sendEmail)  
            {                 
                _sendEmail = sendEmail;  
            }  
    
            //........  
    public async Task<IActionResult> OnPostAsync(string returnUrl = null)  
        {  
            returnUrl ??= Url.Content("~/");  
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();  
            if (ModelState.IsValid)  
            {  
                 
                //.........  
                if (result.Succeeded)  
                {  
                      
                    //.................  
          
                    //.........add this code here......  
                    _sendEmail.send(Input.Email, $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");  
    
                    if (_userManager.Options.SignIn.RequireConfirmedAccount)  
                    {  
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });  
                    }  
                    else  
                    {  
                        await _signInManager.SignInAsync(user, isPersistent: false);  
                        return LocalRedirect(returnUrl);  
                    }  
                }  
                foreach (var error in result.Errors)  
                {  
                    ModelState.AddModelError(string.Empty, error.Description);  
                }  
            }  
    
            // If we got this far, something failed, redisplay form  
            return Page();  
        }  
      
            //.........  
    }  
    

    Finally, You need to change to DisplayConfirmAccountLink = false in RegisterConfirmation.cshtml.cs.

    Now, When user register account, It will send email to user.

    You can also refer to these articles to learn more: Article1, Article2.

    =================Update=====================

    You don't need to remove any code in Register.cshtml.cs. In My answer, I write a class(SendEmail) as a service to send email right? I have used:

    services.AddScoped<SendEmail>();  
    

    to register this service in startup.cs, Now we need to inject this service into Register.cshtml.cs (If you are not familiar with dependency injection in Asp.Net Core, you can refer to this link)

    public class RegisterModel : PageModel  
        {  
            private readonly SignInManager<IdentityUser> _signInManager;  
            private readonly UserManager<IdentityUser> _userManager;  
            private readonly IUserStore<IdentityUser> _userStore;  
            private readonly IUserEmailStore<IdentityUser> _emailStore;  
            private readonly ILogger<RegisterModel> _logger;  
      
            //inject service into this class  
            private readonly SendEmail _sendEmail;  
      
            public RegisterModel(  
                UserManager<IdentityUser> userManager,  
                IUserStore<IdentityUser> userStore,  
                SignInManager<IdentityUser> signInManager,  
                ILogger<RegisterModel> logger,  
                SendEmail sendEmail)  
            {  
                _userManager = userManager;  
                _userStore = userStore;  
                _emailStore = GetEmailStore();  
                _signInManager = signInManager;  
                _logger = logger;  
                _sendEmail = sendEmail;  
            }  
    
           //.............other code........  
           //in OnPostAsync method, we need to use send method in SendEmail service  
    
            public async Task<IActionResult> OnPostAsync(string returnUrl = null)  
     {  
         returnUrl ??= Url.Content("~/");  
         ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();  
         if (ModelState.IsValid)  
         {  
                 
             //.........  
             if (result.Succeeded)  
             {  
                      
                 //.................  
          
                 //use send method in SendEmail service.  
                 _sendEmail.send(Input.Email, $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");  
    
                 if (_userManager.Options.SignIn.RequireConfirmedAccount)  
                 {  
                     return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });  
                 }  
                 else  
                 {  
                     await _signInManager.SignInAsync(user, isPersistent: false);  
                     return LocalRedirect(returnUrl);  
                 }  
             }  
             foreach (var error in result.Errors)  
             {  
                 ModelState.AddModelError(string.Empty, error.Description);  
             }  
         }  
         // If we got this far, something failed, redisplay form  
         return Page();  
     }  
     //.............  
    
    
    }  
    

    In the above code, I injected the SendEmail service into Register.cshtml.cs and called the send method in the SendEmail service in the OnPostAsync method.

    ---------------------------------------------------------------------------------------------------------------------------------------------------------

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Xinran Shen

    1 person found this answer helpful.