Mr. T
Mr. T

Reputation: 4170

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:

Upvotes: 29

Views: 23029

Answers (2)

Marcelo Gondim
Marcelo Gondim

Reputation: 304

You must put async on method.

    public async Task SendAsync(IdentityMessage message)
    {
        using (SmtpClient client = new SmtpClient())
        {
                using (var mailMessage = new MailMessage("[email protected]", message.Destination, message.Subject, message.Body))
                {
                    await client.SendMailAsync(mailMessage);
                }
            }
        }
    }

Upvotes: 9

meziantou
meziantou

Reputation: 21337

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);
    

Upvotes: 31

Related Questions