Sending Emails in Asp.Net Identity using Dependency Injection, Sendgrid and debugging it with Mailtrap.io

Part 1: AspNet Identity and IoC Container Registration

Sounds like I’m making a series of articles about ASP.Net Identity and how to use it with Depenency Injection. Part 1 have seen a lot of hits from Google in just a few days. I suppose it is worth extending the tutorial.

Building up on Part 1 where I wired all Identity components to be injected by Unity container, now I’m going to add emailing service for email confirmation and password reset.

My plan is to use SendGrid as a email service and email debugging service Mailtrap.IO as a hosted fake SMTP server.

EmailService Class

Standard VS template for ApplicationUserManager does not have an implementation for EmailService:

public class EmailService : IIdentityMessageService
{
    public Task SendAsync(IdentityMessage message)
    {
        // Plug in your email service here to send an email.
        return Task.FromResult(0);
    }
}

Let’s create one that uses SendGrid to send emails. Go to http://sendgrid.com/ and get registered: there is a free tier that allows you to send up to 200 emails a day. This is good enough for our testing. Make sure you put your details correctly – all accounts go through moderation before they are allowed to send out emails. And it took a few hours before my account got approved, I also had to reply their support saying that I’m a developer and will only use the account for testing and learning purposes.

Now go install SendGrid nuget package:

PM> Install-Package SendGrid 

Now take a careful look on IIdentityMessageService interface: it has only one method: Task SendAsync(IdentityMessage message). So what information does IdentityMessage contains?
By looking in decompiler I see this:

Identity Message

Basically it is a data container with no methods. We have strings available:

  • Destination – contains email address
  • Subject – email subject
  • Body – text of the email

Now let’s look on SendGrid documentation for C# client. I came up with this as an implementation for the email service:

using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using SendGrid;


namespace IoCIdentity.Identity
{
    public class SendGridEmailService : IIdentityMessageService
    {
        public async Task SendAsync(IdentityMessage message)
        {
            // Create the email object first, then add the properties.
            var myMessage = new SendGridMessage();

            // this defines email and name of the sender
            myMessage.From = new MailAddress("no-reply@tech.trailmax.info", "My Awesome Admin");

            // set where we are sending the email
            myMessage.AddTo(message.Destination);

            myMessage.Subject = message.Subject;

            // make sure all your messages are formatted as HTML
            myMessage.Html = message.Body;

            // Create credentials, specifying your SendGrid username and password.
            var credentials = new NetworkCredential("SendGrid_Username", "SendGrid_Password");

            // Create an Web transport for sending email.
            var transportWeb = new Web(credentials);

            // Send the email.
            await transportWeb.DeliverAsync(myMessage);
        }
    }
}

I’ve renamed EmailService into SendGridEmailService because we are going to have 2 services: one for production, another for testing.

Now it is a time to register this service with DI Container. Open our old friend UnityConfig and add the following line:

// whenever object requires IIdentityMessageService dependency, give them SendGridEmailService
container.RegisterType<IIdentityMessageService, SendGridEmailService>();

Inject this service into ApplicationUserManager:

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store, IIdentityMessageService emailService) : base(store)
    {
        this.EmailService = emailService;
        // the rest of configuration
    }
}

Change AccountController to send out email confirmations on user registration:

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
            var result = await userManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await signInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);

                string code = await userManager.GenerateEmailConfirmationTokenAsync(user.Id);
                var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
                await userManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

                return RedirectToAction("Index", "Home");
            }
            AddErrors(result);
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

All of this is unmodified template code. All I had to do is to uncomment 3 lines related to userManager.SendEmailAsync() and make sure names match.

And now it is a time to test! Hit F5 to start debugging your site, this should launch your web-application. Go to register page, fill in your email, put a password and watch magic. Once you’ve done the registration, you should receive email from your own service! But beware, I got my confirmation email going to spam box in Gmail. Oops!

Check your spam inbox!

Click on link in the email and this should bring you back to your site to email confirmation page /Account/ConfirmEmail.

Now you can stop there: you have your email confirmation sent out and email service class is injected. But the fun only starts!

Fake SMTP Server

When testing account registration, and if you send emails to your real inboxes, you will run out of addresses pretty fast. I’ve got like 5 accounts, but I’d like to try registration process many more times than that. Also I don’t want to worry about sending an email to a real email address, in case I send it to somebody else, not just myself (I’ve done it in the past!).

I have written about Mailtrap.io before and this is another chance to mention this awesome service and how to hook it into your development cycle.

What is Mailtrap.io

Mailtrap is a fake SMTP server for development teams to test, view and share emails sent from the development and staging environments without spamming real customers.

I think this sums up pretty well. I’ll add that there is a pile of fake SMTP servers you can install locally. But I have not seen hosted solutions (other than Mailtrap). When working ina team, centralised, install-free and configuration-free solution works best. Think of a new developer in the team – he/she gets a source code from your version control, hit F5 and up and running with the project. No need to configure fake SMTP server locally.

Now head to Mailtrap.io and get registered. There is a free tier that is just perfect for our small experiment (don’t you love the free tiers in services?).

Anyway, enough blah, more code!

To use Mailtrap service, we need to implement IIdentityMessageService. Mailtrap is quite good with documentation and it already provides a “hello world” sample on many programming languages, including C#:

Hello World for Mailtrap

I’ll use that code as a starting point for our implementation:

using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;


namespace IoCIdentity.Identity
{
    public class MailtrapEmailService : IIdentityMessageService
    {
        public Task SendAsync(IdentityMessage message)
        {
        var client = new SmtpClient
        {
            Host = "mailtrap.io",
            Port = 2525,
            Credentials = new NetworkCredential("24077a300d1d0a919", "36ac3619e3c015"),
            EnableSsl = true,
        };

        var @from = new MailAddress("no-reply@tech.trailmax.info", "My Awesome Admin");
        var to = new MailAddress(message.Destination);

        var mail = new MailMessage(@from, to)
        {
            Subject = message.Subject,
            Body = message.Body,
            IsBodyHtml = true,
        };

        client.Send(mail);

        return Task.FromResult(0);
        }
    }
}

To try it out, I’ll replace what type Unity is injecting as IIdentityMessageService:
Previous line container.RegisterType<IIdentityMessageService, SendGridEmailService>();
Now becomes container.RegisterType<IIdentityMessageService, MailtrapEmailService>();

Start the application and try to register the user: watch your Mailtrap inbox receive first intercepted email:

Send to what email address???

That is pretty cool. You can give a random email address on the registration and only you will see the email, it won’t go anywhere further than the fake inbox. There is an option to redirect all incoming fake emails, but I have not found the use case for this yet.

Inject Different Classes in Dev and Prod

Now we have 2 different implementations of email service that can be used in Identity Framework. I would like to configure our DI container to use the implementation most appropriate to the case. If we are in production, use SendgridEmailService. If we are testing or developing use MailtrapUserService.

I find the problem of deciding if we are in production or in testing pretty hard. Given that code on developers machines are usually executed in Debug mode, we can easily check for that. But when it comes to Testing environment, it is usually used by QA people (or sometimes clients) and is not running in Debug mode. Ideally Testing environment is identical to production, so there is not many “in-code flags” that we can use.
In the past I have added a setting in web.config/appSettings: <add key="isProduction" value="false" /> and checked for this setting. For production, this setting was changed during the deployment pipeline (web.config transformation).

But for the purposes of our little tutorial, we can rely on checking if the code is in Debug mode or if the request is local to the server where it is hosted. Here is the registration part:

container.RegisterType<IIdentityMessageService, SendGridEmailService>("production");
container.RegisterType<IIdentityMessageService, MailtrapEmailService>("debugging");

container.RegisterType<IIdentityMessageService>(new InjectionFactory(c =>
    {
        try
        {
            // not in debug mode and not local request => we are in production
            if (!HttpContext.Current.IsDebuggingEnabled && !HttpContext.Current.Request.IsLocal)
            {
                return c.Resolve<IIdentityMessageService>("production");
            }
        }
        catch (Exception)
        {
            // Catching exceptions for cases if there is no Http request available
        }
        return c.Resolve<IIdentityMessageService>("debugging");
    }));

Now this looks scary. Let’s talk through each bit separately. This line:

container.RegisterType<IIdentityMessageService, SendGridEmailService>("production");

is telling the container to register type SendGridEmailService as an implementation for interface IIdentityMessageService and add named key to this registration as “production”. Pretty much the same happens on the next line about MailtrapEmailService, only the registration key is “debugging”. Basically this is some sort of alias for the registration. This works for the cases when we have more than one implementation class registered for one interface, just as we have at the moment.

Registration for IIdentityMessageService with InjectionFactory is the place where we decide which of the implementations to go for. I check if we are running not in debug and http request is not local, then it is production code and we need SendgridEmailService, otherwise we need MailtrapEmailService. I do wrap checking for conditions into try/catch block: Http.Current will throw exceptions in cases when no http request is available (this can happen if you for some reason try to execute this code in Application_Start()).

I do resolution of concrete implementations through container and named resolution:

return c.Resolve<IIdentityMessageService>("production");

This call matches provided key "production" to previous registrations for the requested interface IIdentityMessageService with this key, and SendgridEmailService should be resolved.

Instead of named resolutions I could have created concrete classes:

return new SendgridEmailService();

But if these classes evolve and dependencies are introduced (e.g. ILoggingService is injected), we will need to go back to this code and add dependencies. If we do resolution from the container, it will take care of the dependencies, as long as they are all registered.

Resetting Password Through Email

So far I’ve been getting an email only on user registration. But I could not reset the password. Let’s fix this to complete our solution.

AccountController already has all the stuff required for password resetting. All you need to do is uncomment some code:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = await userManager.FindByNameAsync(model.Email);
        if (user == null || !(await userManager.IsEmailConfirmedAsync(user.Id)))
        {
            // Don't reveal that the user does not exist or is not confirmed
            return View("ForgotPasswordConfirmation");
        }

        // Send an email with this link
        var code = await userManager.GeneratePasswordResetTokenAsync(user.Id);
        var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
        await userManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");
        return RedirectToAction("ForgotPasswordConfirmation", "Account");
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

And add the link to this action from login page Login.cshtml:

<p>
    @Html.ActionLink("Reset password", "ForgotPassword")
</p>

That’s it – go try reset your password for the accounts you already created – all password reset passwords should go through to Mailtrap.

Give Me The Codez!

Here is the the full source code based on Part 1 and added code above

P.S. I’m struggling what should the next article in the series should be. I’m thinking 2FA and send out SMS, but there won’t be much DI happening there? Please suggest in comments.