locked
Email not sending using asp.net core and send grid RRS feed

  • Question

  • User-183185495 posted

    Ok in asp.net core I have setup send grid to handle the email confirmations however the user just gets into the system right away. It doesnt send the email out and they just get logged in. I am using .net core 3.1 btw.

    Here is my code Register.cshtml

    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,FirstName=Input.FirstName,LastName=Input.LastName };
            //ADD CLAIM HERE!!!!
              
            var result = await _userManager.CreateAsync(user, Input.Password);
    
            var test = await _userManager.AddClaimAsync(user, new Claim("FullName", user.FirstName + " " + user.LastName));
    
            await _userManager.AddToRoleAsync(user, "admin");
    
    
            if (result.Succeeded)
            {
                _logger.LogInformation("User created a new account with password.");
    
                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>.");
    
                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);
            }
        }
        ViewData["roles"] = _roleManager.Roles.ToList();
    
        // If we got this far, something failed, redisplay form
        return Page();
     }
    }

    Email Sender

    public class EmailSender : IEmailSender {
        public EmailSender(IOptions<AuthMessageSenderOptions> optionsAccessor) {
            Options = optionsAccessor.Value;
        }
    
        public AuthMessageSenderOptions Options { get; } //set only via Secret Manager
    
        public Task SendEmailAsync(string email, string subject, string message) {
            return Execute(Options.SendGridKey, subject, message, email);
        }
    
        public Task Execute(string apiKey, string subject, string message, string email) {
            var client = new SendGridClient(apiKey);
            var msg = new SendGridMessage() {
                From = new EmailAddress("Joe@contoso.com", Options.SendGridUser),
                Subject = subject,
                PlainTextContent = message,
                HtmlContent = message
            };
            msg.AddTo(new EmailAddress(email));
    
            // Disable click tracking.
            // See https://sendgrid.com/docs/User_Guide/Settings/tracking.html
            msg.SetClickTracking(false, false);
    
            return client.SendEmailAsync(msg);
    
    }

    AuthMessageSenderOptions

    namespace MISSystem.Web.Services {
       public class AuthMessageSenderOptions  {
       public string SendGridUser { get; set; }
       public string SendGridKey { get; set; }
    }    

    CustomEmailConfirmationTokenProvider.cs

    public class CustomEmailConfirmationTokenProvider<TUser>
                                       : DataProtectorTokenProvider<TUser> where TUser : class {
        public CustomEmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
            IOptions<EmailConfirmationTokenProviderOptions> options,
            ILogger<DataProtectorTokenProvider<TUser>> logger)
                                              : base(dataProtectionProvider, options, logger) {
    
        }
    }
    public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions {
        public EmailConfirmationTokenProviderOptions() {
            Name = "EmailDataProtectorTokenProvider";
            TokenLifespan = TimeSpan.FromHours(4);
        }
    }

    Statup.cs ConfiguratService

    services.Configure<IdentityOptions>(options =>
    {
              
        // Default Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;
    });
    services.ConfigureApplicationCookie(config => {
        config.Cookie.Name = "Identity.Cookie";
        config.LoginPath = "/Identity/Account/Login/";
    });
    services.AddTransient<MISDBContextSeedData>();
    services.AddSingleton<ISharedResource, SharedResource>();
    // using WebPWrecover.Services;
    services.AddTransient<IEmailSender, EmailSender>();
    services.Configure<AuthMessageSenderOptions>(Configuration);
    
    
    services.AddAuthentication(options => {
        options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
        options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
        options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
    });

    My Configure Method

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, MISDBContextSeedData seeder)  
    {
            var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
            app.UseRequestLocalization(locOptions.Value);
    
            seeder.SeedAdminUser();
    
        var supportedCultures = new[]
        {
        new CultureInfo("en-US"),
        new CultureInfo("en-GB"),
        new CultureInfo("es"),
        new CultureInfo("fr")
        };
        app.UseRequestLocalization(new RequestLocalizationOptions() {
        DefaultRequestCulture = new RequestCulture("en-GB"),
        SupportedCultures = supportedCultures,
        SupportedUICultures = supportedCultures
        });
        if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
        } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
        }
            //NOTE this line must be above .UseMvc() line.
            app.UseNToastNotify();
            app.UseSession();
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=MISObjects}/{action=Index}/{id?}");
        endpoints.MapRazorPages();
        });

    Edit 2

    InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'MISSystem.Web.Areas.Identity.Pages.Account.RegisterConfirmationModel'

    services.AddIdentity<ApplicationUser, IdentityRole>(options => options.SignIn.RequireConfirmedAccount =true)
    

    Thursday, July 30, 2020 9:19 PM

Answers

  • User888730286 posted

    In your EmailSender class, you are attempting to send the email from Joe@contoso.com, try placing the email you used during the SendGrid signup. You may need to verify your sender email too. Login to SendGrid and then go to Settings > Sender Authentication and scroll down to Single Sender Verification to ensure that email is authorized. Hope it works for you!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 31, 2020 12:07 AM

All replies

  • User888730286 posted

    In your EmailSender class, you are attempting to send the email from Joe@contoso.com, try placing the email you used during the SendGrid signup. You may need to verify your sender email too. Login to SendGrid and then go to Settings > Sender Authentication and scroll down to Single Sender Verification to ensure that email is authorized. Hope it works for you!

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, July 31, 2020 12:07 AM
  • User711641945 posted

    Hi roguenidb,

    Edit 2

    InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Microsoft.AspNetCore.Identity.IdentityUser]' while attempting to activate 'MISSystem.Web.Areas.Identity.Pages.Account.RegisterConfirmationModel'

    Be sure your ResigterConfirmationModel is like below:

    public class RegisterConfirmationModel : PageModel
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IEmailSender _sender;
    
        public RegisterConfirmationModel(UserManager<ApplicationUser> userManager, IEmailSender sender)
        {
            _userManager = userManager;
            _sender = sender;
        }
    }

    Best Regards,

    Rena

    Friday, July 31, 2020 7:47 AM