Search code examples
c#asp.net-identitysmtpclient

Asp.Net Identity 2.0 - How to Implement IIdentityMessageService to do Async SMTP using SmtpClient?


I've implemented a simple EmailService for Asp.Net Identity 2.0 (via the IIdentityMessageService interface.

    public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // convert IdentityMessage to a MailMessage
        var email = 
           new MailMessage(new MailAddress("[email protected]", "(do not reply)"), 
           new MailAddress(message.Destination))
        {
            Subject = message.Subject,
            Body = message.Body,
            IsBodyHtml = true
        };

        using (var client = new SmtpClient()) // SmtpClient configuration comes from config file
        {
            return client.SendMailAsync(email);
        }
    }
}

To send an email, I go through UserManager:

await _userManager.SendEmailAsync(user.Id, "Confirm your account","Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");

The problem is that I get a System.Threading.Tasks.TaskCanceledException when I call SendEmailAsync() and it's not clear why.

If I send email synchronously (client.Send(email)), everything works fine.

So my questions are:

  • How do I prevent the TaskCanceledException from getting thrown? and (assuming I can overcome this error),

  • How should I go about communicating errors during email sending back to the client (i.e., "no such user here" type responses from the SmtpClient?


Solution

  • Your problem is that SmtpClient is disposed before the email is sent.

    Two ways:

    • Await the SendMailAsync result

      using (var client = new SmtpClient())
      {
          await client.SendMailAsync(email);
      }
      
    • Register the SendCompleted event and dispose the SmtpClient only after the message is sent

      var client = new SmtpClient();
      client.SendCompleted += (s, e) => {
          client.Dispose();
      };
      return client.SendMailAsync(message);