How to send email using gmail smtp in an ASP.NET MVC application

vs-screen-shot-w-logo

Most public facing asp.net mvc web applications have an email feature to notify users of a successful registration. It’s very common for developers to use gmail smtp for this feature as seen in this question on stackoverflow. If you want to skip all the details and get the gmail integration code check out my github space here. If not, read on.

The following article demonstrates the use of gmail smtp integration in a sample insurance lead generation site (similar to one I worked on before) built using the default ASP.NET MVC 4 application template. The application is architected in a way that will help isolate common issues associated with gmail smtp integration.

Isolating the gmail smtp integration is done leveraging a separate business layer which can be used in any .NET application, Interface based development, IoC (Inversion of Control) using Autofac, unit testing with NUnit, and good ol ASP.NET MVC. I like to follow a TDD approach so the steps will follow.

The first task is to setup the interfaces & models to send emails, which is a fairly simple task.

    public interface IEmailService
    {
        bool SendEmailMessage(EmailMessage message);
    }
    public class SmtpConfiguration
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string Host { get; set; }
        public int Port { get; set; }
        public bool Ssl { get; set; }
    }

    public class EmailMessage
    {
        public string ToEmail { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }
        public bool IsHtml { get; set; }
    }

Next, we setup the Unit tests to isolate the gmail integration. This helps us take care of all the SMTP authentication issues that everyone usually runs across when doing this integration. Run this test to your hearts’ content to make sure things are working correctly.

        public EmailTests()
        {
            _emailService = new GmailEmailService();
        }

        [Test]
        public void send_email_via_gmail()
        {
            var email = new EmailMessage
            {
                IsHtml = false,
                Subject = "Gmail unit test email",
                ToEmail = "your.test.email@gmail.com",
                Body = String.Format("Gmail unit test body sent at {0:D}", DateTime.Now)
            };
            var success = _emailService.SendEmailMessage(email);
            Assert.IsTrue(success);
        }
    }
}

The actual implementation is also quite simple. It is usually just the SMTP settings that cause common timeout errors. Some of the key settings to keep an eye on are

  • EnableSsl = true
  • port = 587

 

        public bool SendEmailMessage(EmailMessage message)
        {
            var success = false;
            try
            {
                var smtp = new SmtpClient
                {
                    Host = _config.Host,
                    Port = _config.Port,
                    EnableSsl = _config.Ssl,
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    UseDefaultCredentials = false,
                    Credentials = new NetworkCredential(_config.Username, _config.Password)
                };

                using (var smtpMessage = new MailMessage(_config.Username, message.ToEmail))
                {
                    smtpMessage.Subject = message.Subject;
                    smtpMessage.Body = message.Body;
                    smtpMessage.IsBodyHtml = message.IsHtml;
                    smtp.Send(smtpMessage);
                }

                success = true;
            }
            catch (Exception ex)
            {
                //todo: add logging integration
                //throw;
            }

            return success;
        }
    }
GmailEmailService.csview rawview file on GitHub

I like getting the SMTP settings out of an app.coinfig or web.config file like so .

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="GmailUserName" value="[your-email@gmail.com]"/>
    <add key="GmailPassword" value="[your-gmail-password]"/>
    <add key="GmailHost" value="smtp.gmail.com"/>
    <add key="GmailPort" value="587"/>
    <add key="GmailSsl" value="true"/>
  </appSettings>
</configuration>
        public GmailEmailService()
        {
            _config = new SmtpConfiguration();
            var gmailUserName = ConfigurationManager.AppSettings[GmailUserNameKey];
            var gmailPassword = ConfigurationManager.AppSettings[GmailPasswordKey];
            var gmailHost = ConfigurationManager.AppSettings[GmailHostKey];
            var gmailPort = Int32.Parse(ConfigurationManager.AppSettings[GmailPortKey]);
            var gmailSsl = Boolean.Parse(ConfigurationManager.AppSettings[GmailSslKey]);
            _config.Username = gmailUserName;
            _config.Password = gmailPassword;
            _config.Host = gmailHost;
            _config.Port = gmailPort;
            _config.Ssl = gmailSsl;
        }
GmailEmailService.csview rawview file on GitHub

Now that all the pieces are in place you should be able to run your unit tests through an NUnit test runner and receive your test email message.

Once you are sure all gmail SMTP authentication & settings issues are correct you are ready to begin ASP.NET MVC integration. I usually achieve this in my projects by leveraging Autofac via the Nuget package manager & wiring up dependencies in Global.asax events. Pay attention to the last line in the Application_Start event.

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AutofacConfig.RegisterDependencies();
        }
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Framework.Implementations;
using Framework.Interfaces;

namespace OnlineInsuranceAgency
{
    public class AutofacConfig
    {
        public static void RegisterDependencies()
        {
            var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof(MvcApplication).Assembly);
            builder.RegisterFilterProvider(); //Inject Properties Into FilterAttributes section of MvcIntegration
            builder.RegisterSource(new ViewRegistrationSource());
            builder.RegisterType<GmailEmailService>().As<IEmailService>();
            var container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
        }

    }
}

If you’re not familiar with DI(dependency injection) or IoC, the style I use leverages Autofac as a DI container which instantiates controller classes and injects any concrete class which matches the Autofac mappings we have set and the interface signature used as constructor parameters. Notice how the IEmailService interface is both mapped in our AutofacConfig class and used as a parameter in the AccountController constructors.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Framework.Interfaces;
using Framework.Models;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
using OnlineInsuranceAgency.Models;

namespace OnlineInsuranceAgency.Controllers
{
    [Authorize]
    public class AccountController : Controller
    {
        public AccountController(IEmailService emailService)
            : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())),emailService)
        {
        }

        public AccountController(UserManager<ApplicationUser> userManager, IEmailService emailService)
        {
            UserManager = userManager;
            EmailService = emailService;
        }

        private IEmailService EmailService { get; set; }
        public UserManager<ApplicationUser> UserManager { get; private set; }

        //
AccountController.csview rawview file on GitHub

The final step to finish off our initial requirement of sending emails on registration is to create the email message content we would like to send and use it within our controller class. Notice lines 14 to 22.

        // POST: /Account/Register
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser() { UserName = model.UserName };
                var result = await UserManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await SignInAsync(user, isPersistent: false);
                    var message = new EmailMessage();
                    message.ToEmail = model.EmailAddress;
                    message.Subject = "Insurance Website Registration";
                    message.IsHtml = false;
                    message.Body =
                        String.Format("You have succesfully registered for Vanderbuilt Insurance with the following" +
                                      "username: {0}", model.UserName);

                    var status = EmailService.SendEmailMessage(message);

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

            // If we got this far, something failed, redisplay form
            return View(model);
        }
AccountController.csview rawview file on GitHub

I hope you found this article helpful. Please feel free to leave comments & sign up for our newsletter if you’d like updates to new content we put out.

Leave A Response