Introduction

ASP.NET Core Identity's default UI (AddDefaultIdentity) generates email confirmation tokens and calls IEmailSender.SendEmailAsync, but the framework does not include a default email sender implementation. Without registering a concrete IEmailSender, confirmation emails are silently dropped — the registration succeeds but the user never receives the confirmation link. This also affects password reset emails and two-factor authentication codes.

Symptoms

  • User registration succeeds but no confirmation email received
  • Password reset link never arrives
  • No errors logged during registration
  • IEmailSender injected but sends nothing
  • Two-factor authentication code not delivered

Common Causes

  • IEmailSender not registered in DI container
  • SMTP configuration missing or incorrect
  • Email sender throws but exception is caught silently
  • SendEmailAsync called with empty or invalid email address
  • Third-party email service API key not configured

Step-by-Step Fix

  1. 1.Implement IEmailSender with SMTP:
  2. 2.```csharp
  3. 3.public class SmtpEmailSender : IEmailSender
  4. 4.{
  5. 5.private readonly SmtpSettings _settings;
  6. 6.private readonly ILogger<SmtpEmailSender> _logger;

public SmtpEmailSender(IConfiguration config, ILogger<SmtpEmailSender> logger) { _settings = config.GetSection("Smtp").Get<SmtpSettings>(); _logger = logger; }

public async Task SendEmailAsync(string toEmail, string subject, string htmlMessage) { if (string.IsNullOrWhiteSpace(toEmail)) { _logger.LogWarning("Attempted to send email to empty address"); return; }

using var client = new SmtpClient(_settings.Host, _settings.Port); client.EnableSsl = _settings.EnableSsl;

if (!string.IsNullOrEmpty(_settings.Username)) { client.Credentials = new NetworkCredential(_settings.Username, _settings.Password); }

var mail = new MailMessage(_settings.FromEmail, toEmail) { Subject = subject, Body = htmlMessage, IsBodyHtml = true };

try { await client.SendMailAsync(mail); _logger.LogInformation("Confirmation email sent to {Email}", toEmail); } catch (Exception ex) { _logger.LogError(ex, "Failed to send email to {Email}", toEmail); throw; } } }

public class SmtpSettings { public string Host { get; set; } = "smtp.gmail.com"; public int Port { get; set; } = 587; public bool EnableSsl { get; set; } = true; public string? Username { get; set; } public string? Password { get; set; } public string FromEmail { get; set; } = "noreply@myapp.com"; }

// Registration in Program.cs builder.Services.AddTransient<IEmailSender, SmtpEmailSender>(); builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("Smtp")); ```

  1. 1.Use SendGrid for production email delivery:
  2. 2.```csharp
  3. 3.// Install: SendGrid
  4. 4.using SendGrid;
  5. 5.using SendGrid.Helpers.Mail;

public class SendGridEmailSender : IEmailSender { private readonly ISendGridClient _client; private readonly string _fromEmail; private readonly ILogger<SendGridEmailSender> _logger;

public SendGridEmailSender(IConfiguration config, ILogger<SendGridEmailSender> logger) { _client = new SendGridClient(config["SendGrid:ApiKey"]); _fromEmail = config["SendGrid:FromEmail"]; _logger = logger; }

public async Task SendEmailAsync(string toEmail, string subject, string htmlMessage) { var msg = new SendGridMessage { From = new EmailAddress(_fromEmail, "MyApp"), Subject = subject, HtmlContent = htmlMessage }; msg.AddTo(new EmailAddress(toEmail));

var response = await _client.SendEmailAsync(msg);

if (!response.IsSuccessStatusCode) { var body = await response.Body.ReadAsStringAsync(); _logger.LogError("SendGrid failed: {Status} - {Body}", response.StatusCode, body); throw new InvalidOperationException($"SendGrid failed: {response.StatusCode}"); }

_logger.LogInformation("Email sent to {Email} via SendGrid", toEmail); } }

// Program.cs builder.Services.AddTransient<IEmailSender, SendGridEmailSender>(); ```

Prevention

  • Always register a concrete IEmailSender when using Identity with email confirmation
  • Log email send results for debugging
  • Use a transactional email service (SendGrid, Mailgun, SES) in production
  • Test email delivery in staging environment
  • Add email queue for retry on transient failures
  • Monitor email bounce and complaint rates