Answered by:
Email not sending using asp.net core and send grid

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