'ASP.net Core Identity 3.1

What is the suitable service to provide email confirmation and password reset. i have tried smtp but after six attempts actually it considered those emails as spams and was blocked permanently and sendgrid doesn't gave me access to the service. When the user click on the register button in the registration form the account is created automatically without sending an email but it works well when the admin is trying to register either a new user or admin.

Here is the email sender class:

  public async Task SendEmailAsync(string email, string subject, string htmlMessage)
    {
        var fromMail = "";
        var fromPassword = "";

        var message = new MailMessage();
        message.From = new MailAddress(fromMail);
        message.Subject = subject;
        message.To.Add(email);
        message.Body = $"<html><body>{htmlMessage}</body></html>";
        message.IsBodyHtml = true;

        var smtpClient = new SmtpClient(host:"smtp-mail.outlook.com")
        {
            Port = 587,
            Credentials = new NetworkCredential(fromMail, fromPassword),
            EnableSsl = true,
        };
        smtpClient.Send(message);
    }

And Here is the Register.cshtml.cs

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
    {
        returnUrl = returnUrl ?? Url.Content("~/");
        ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = Input.Email,
                Email = Input.Email,
                Name=Input.Name,
                PhoneNumber=Input.PhoneNumber,
                StreetAddress=Input.StreetAddress,
                City=Input.City,
                Governorate=Input.Governorate,
                PostalCode=Input.PostalCode
            
            };
            var result = await _userManager.CreateAsync(user, Input.Password);
            if (result.Succeeded)
            {
                //determine role of new user account
                if(! await _roleManager.RoleExistsAsync(SD.AdminUser))
                {
                  await  _roleManager.CreateAsync(new IdentityRole(SD.AdminUser));
                }
                if (!await _roleManager.RoleExistsAsync(SD.EndUser))
                {
                    await _roleManager.CreateAsync(new IdentityRole(SD.EndUser));
                }

                string role = HttpContext.Request.Form["rdUserRole"].ToString();

                if (string.IsNullOrEmpty(role))
                {
                    await _userManager.AddToRoleAsync(user, SD.EndUser);
                    await _signInManager.SignInAsync(user, isPersistent: false);
                    return LocalRedirect(returnUrl);
                }
                else
                {
                    await _userManager.AddToRoleAsync(user, role);

                }
                
                _logger.LogInformation("User created a new account with password.");

                if (_userManager.Options.SignIn.RequireConfirmedAccount)
                {
                    var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                }
                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                    protocol: Request.Scheme);

                await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");



            }
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }

        // If we got this far, something failed, redisplay form
        return Page();
    }

Here is the registerconfirmation.cshtml.cs:

     public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return NotFound();
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;

        DisplayConfirmAccountLink = true;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }


Solution 1:[1]

I checked your codes and it seems that you need to move the codes:

 await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

before:

if (_userManager.Options.SignIn.RequireConfirmedAccount)
                {
                    var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                }

In your logical,if"_userManager.Options.SignIn.RequireConfirmedAccount" is set true by default,you will never send the confirm e-mail

And You could read the offcial document related with your codes:

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-6.0&tabs=visual-studio#examine-register

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ruikai Feng