Notifications to end-users are a very crucial need for interactive web development. Popular forms of notifications in web development are emails and SMS alerts. It is essentially a responsibility of the websites (that are maintaining end-user accounts) to notify end-users about various interactions happening with their accounts, simply, to feel more secure, more aware, and more in control of their accounts with third-party products.
In today's tutorial, I will demonstrate the method of sending SMTP email notification using ASP.NET MVC5 platform.
Prerequisites
Following are some prerequisites before you proceed any further in this tutorial:
- Knowledge about ASP.NET MVC5.
- Knowledge about HTML.
- Knowledge about Javascript.
- Knowledge about AJAX.
- Knowledge about CSS.
- Knowledge about Bootstrap.
- Knowledge about C# programming.
- Knowledge about C# LINQ.
- Knowledge about JQuery.
You can download the complete source code for this tutorial or you can follow the step by step discussion below. The sample code is developed in Microsoft Visual Studio 2015 Enterprise.
Let's begin now.
Step 1
Create new MVC5 web application project and name it "EmailNotification".
Step 2
I like to keep my sensitive information into resource (.resx) files instead of web.config file. So, create a "Resources/Constants/EmailInfo.resx" resource (.resx) file and ensure that "Access Modifier" of the file is "Public" as shown below i.e.
Since I am going to use a Gmail account as a source email address for sending email notifications, hence, I will be using "smtp.gmail.com" as my host type configuration with port "587" which are essential configuration properties for SMTP protocol. You can use "587" port for other common email host types as well. Below are the list of host type configuration for other common email host types i.e.
- GMAIL SMTP HOST -> smtp.gmail.com
- YAHOO SMTP HOST -> smtp.mail.yahoo.com
- HOTMAIL/LIVE SMTP HOST -> smtp.live.com
- OUTLOOK/Exchange Server SMTP HOST -> smtp-mail.outlook.com
In order to send email notifications from your website to end-users of your web product, you need to have a source email account. The concept is simple here, you need an email account to send a notification to another email account. The only difference is that your source email account should not be your personal account, so, it cannot be misused. For example, when you receive email notifications from your social media accounts, notice that they specifically write "do-not-reply" in the name of the email address or mention that at the end of the email notifications that not to reply to this email address. The reason is simple -- they have fixed that particular email account for sending notifications only, according to the actions you perform on their websites. So, here below are the mandatory configuration properties within your code to configure your source email address for sending email notifications to the end-users i.e.:
- FROM_EMAIL_ACCOUNT
- FROM_EMAIL_PASSWORD
- SMTP_HOST_TYPE
- SMTP_PORT
Step 3
Create the following list of properties within the "Resources/Constants/EmailInfo.resx" resource (.resx) file as shown below, i.e.
Notice in the above that I have left "FROM_EMAIL_ACCOUNT" and "FROM_EMAIL_PASSWORD" configuration properties empty i.e.:
These are your source email account email addresses and passwords. You need to update that while executing this tutorial.
Step 4
Now, Open "Views\Shared\_Layout.cshtml" page and replace following code in it:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>@ViewBag.Title</title>
- @Styles.Render("~/Content/css")
- @Scripts.Render("~/bundles/modernizr")
-
-
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
-
- </head>
- <body>
- <div class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- </div>
- </div>
- </div>
- <div class="container body-content">
- @RenderBody()
- <hr />
- <footer>
- <center>
- <p><strong>Copyright © @DateTime.Now.Year - <a href="http://wwww.asmak9.com/">Asma's Blog</a>.</strong> All rights reserved.</p>
- </center>
- </footer>
- </div>
-
- @*Scripts*@
- @Scripts.Render("~/bundles/jquery")
-
- @Scripts.Render("~/bundles/jqueryval")
- @Scripts.Render("~/bundles/bootstrap")
-
-
- @Scripts.Render("~/scripts/custom-form")
-
- @RenderSection("scripts", required: false)
- </body>
- </html>
In the above code, I have simply created a basic layout design for the web pages and include necessary references to the require libraries.
Step 5
Now, create "Models\EmailNotifyViewModel.cs" file and replace following code in this file:
-
-
-
-
-
-
-
- namespace EmailNotification.Models
- {
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
-
-
-
-
- public class EmailNotifyViewModel
- {
- #region Properties
-
-
-
-
- [Required]
- [Display(Name = "To (Email Address)")]
- public string ToEmail { get; set; }
-
- #endregion
- }
- }
In the above code, I have simply created my View Model to attach it with the corresponding UI.
Step 6
Now, create "Controllers\EmailNotifyController.cs.cs" file and replace following code in it:
-
-
-
-
-
-
-
- namespace EmailNotification.Controllers
- {
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.Mvc;
- using Models;
- using System.Threading.Tasks;
- using System.Net.Mail;
- using Resources.Constants;
- using System.Net;
-
-
-
-
- public class EmailNotifyController : Controller
- {
- #region Index view method.
-
- #region Get: /EmailNotify/Index method.
-
-
-
-
-
- public ActionResult Index()
- {
- try
- {
- }
- catch (Exception ex)
- {
-
- Console.Write(ex);
- }
-
-
- return this.View();
- }
-
- #endregion
-
- #region POST: /EmailNotify/Index
-
-
-
-
-
-
- [HttpPost]
- [AllowAnonymous]
- [ValidateAntiForgeryToken]
- public async Task<ActionResult> Index(EmailNotifyViewModel model)
- {
- try
- {
-
- if (ModelState.IsValid)
- {
-
- string emailMsg = "Dear " + model.ToEmail + ", <br /><br /> Thist is test <b style='color: red'> Notification </b> <br /><br /> Thanks & Regards, <br />Asma Khalid";
- string emailSubject = EmailInfo.EMAIL_SUBJECT_DEFAUALT + " Test";
-
-
- await this.SendEmailAsync(model.ToEmail, emailMsg, emailSubject);
-
-
-
- return this.Json(new { EnableSuccess = true, SuccessTitle = "Success", SuccessMsg = "Notification has been sent successfully! to '" + model.ToEmail + "' Check your email." });
- }
- }
- catch (Exception ex)
- {
-
- Console.Write(ex);
-
-
- return this.Json(new { EnableError = true, ErrorTitle = "Error", ErrorMsg = ex.Message });
- }
-
-
- return this.Json(new { EnableError = true, ErrorTitle = "Error", ErrorMsg = "Something goes wrong, please try again later" });
- }
-
- #endregion
-
- #endregion
-
- #region Helper
-
- #region Send Email method.
-
-
-
-
-
-
-
-
- public async Task<bool> SendEmailAsync(string email, string msg, string subject = "")
- {
-
- bool isSend = false;
-
- try
- {
-
- var body = msg;
- var message = new MailMessage();
-
-
- message.To.Add(new MailAddress(email));
- message.From = new MailAddress(EmailInfo.FROM_EMAIL_ACCOUNT);
- message.Subject = !string.IsNullOrEmpty(subject) ? subject : EmailInfo.EMAIL_SUBJECT_DEFAUALT;
- message.Body = body;
- message.IsBodyHtml = true;
-
- using (var smtp = new SmtpClient())
- {
-
- var credential = new NetworkCredential
- {
- UserName = EmailInfo.FROM_EMAIL_ACCOUNT,
- Password = EmailInfo.FROM_EMAIL_PASSWORD
- };
-
-
- smtp.Credentials = credential;
- smtp.Host = EmailInfo.SMTP_HOST_GMAIL;
- smtp.Port = Convert.ToInt32(EmailInfo.SMTP_PORT_GMAIL);
- smtp.EnableSsl = true;
-
-
- await smtp.SendMailAsync(message);
-
-
- isSend = true;
- }
- }
- catch (Exception ex)
- {
-
- throw ex;
- }
-
-
- return isSend;
- }
-
- #endregion
-
- #endregion
- }
- }
The above piece of code consists of both HttpGet & HttpPost Index(...) methods and the key helper method SendEmailAsync(...). HttpGet Index(...) method will return the details of the Index view page. While HttpPost Index(...) method will capture end-user inputs which is an email address for the recipient where I want to send my email notification. Notice that in HttpPost Index(...) method, I have composed a fix email notification message:
-
- string emailMsg = "Dear " + model.ToEmail + ", <br /><br /> Thist is test <b style='color: red'> Notification </b> <br /><br /> Thanks & Regards, <br />Asma Khalid";
You can compose your own email notification message, static or dynamic; it's completely up to you.
Now, let's look closely at the key helper method "SendEmailSync(...)" which will actually send the email notification to the recipient email address which I have obtained from the end-user:
- #region Send Email method.
-
-
-
-
-
-
-
-
- public async Task<bool> SendEmailAsync(string email, string msg, string subject = "")
- {
-
- bool isSend = false;
-
- try
- {
-
- var body = msg;
- var message = new MailMessage();
-
-
- message.To.Add(new MailAddress(email));
- message.From = new MailAddress(EmailInfo.FROM_EMAIL_ACCOUNT);
- message.Subject = !string.IsNullOrEmpty(subject) ? subject : EmailInfo.EMAIL_SUBJECT_DEFAUALT;
- message.Body = body;
- message.IsBodyHtml = true;
-
- using (var smtp = new SmtpClient())
- {
-
- var credential = new NetworkCredential
- {
- UserName = EmailInfo.FROM_EMAIL_ACCOUNT,
- Password = EmailInfo.FROM_EMAIL_PASSWORD
- };
-
-
- smtp.Credentials = credential;
- smtp.Host = EmailInfo.SMTP_HOST_GMAIL;
- smtp.Port = Convert.ToInt32(EmailInfo.SMTP_PORT_GMAIL);
- smtp.EnableSsl = true;
-
-
- await smtp.SendMailAsync(message);
-
-
- isSend = true;
- }
- }
- catch (Exception ex)
- {
-
- throw ex;
- }
-
-
- return isSend;
- }
-
- #endregion
In the above code, I am using "SmtpClient" to send email notification to the recipient email address. I first set essential configuration for message body with recipient email address:
-
- var body = msg;
- var message = new MailMessage();
-
-
- message.To.Add(new MailAddress(email));
- message.From = new MailAddress(EmailInfo.FROM_EMAIL_ACCOUNT);
- message.Subject = !string.IsNullOrEmpty(subject) ? subject : EmailInfo.EMAIL_SUBJECT_DEFAUALT;
- message.Body = body;
- message.IsBodyHtml = true;
Next, I have configured my source email address account with host type & port settings and finally, send the email notification to the recipient:
- using (var smtp = new SmtpClient())
- {
-
- var credential = new NetworkCredential
- {
- UserName = EmailInfo.FROM_EMAIL_ACCOUNT,
- Password = EmailInfo.FROM_EMAIL_PASSWORD
- };
-
-
- smtp.Credentials = credential;
- smtp.Host = EmailInfo.SMTP_HOST_GMAIL;
- smtp.Port = Convert.ToInt32(EmailInfo.SMTP_PORT_GMAIL);
- smtp.EnableSsl = true;
-
-
- await smtp.SendMailAsync(message);
-
-
- isSend = true;
- }
Step 7
To tie everything together, let's create the UI ajax form. So, create "Views\EmailNotify\Index.cshtml" file and replace following code in it i.e.
- @using EmailNotification.Models
-
- @model EmailNotification.Models.EmailNotifyViewModel
-
- @{
- ViewBag.Title = "ASP.NET MVC5: SMTP Email Notification";
- }
-
-
- <div class="row">
- <div class="panel-heading">
- <div class="col-md-8">
- <h3>
- <i class="fa fa-file-text-o"></i>
- <span>ASP.NET MVC5: SMTP Email Notification</span>
- </h3>
- </div>
- </div>
- </div>
-
- <div class="row">
- <section class="col-md-4 col-md-push-4">
- @using (Ajax.BeginForm("Index", "EmailNotify", new AjaxOptions { HttpMethod = "POST", OnSuccess = "onEmailNotifySuccess" }, new { @id = "EmailNotifyformId", @class = "form-horizontal", role = "form" }))
- {
- @Html.AntiForgeryToken()
-
- <div class="well bs-component">
- <br />
-
- <div class="row">
- <div class="col-md-12 col-md-push-2">
- <div class="form-group">
- <div class="col-md-10 col-md-pull-1">
- @Html.TextBoxFor(m => m.ToEmail, new { placeholder = Html.DisplayNameFor(m => m.ToEmail), @class = "form-control" })
- @Html.ValidationMessageFor(m => m.ToEmail, "", new { @class = "text-danger custom-danger" })
- </div>
- </div>
-
- <div class="form-group">
- <div class="col-md-18">
- </div>
- </div>
-
- <div class="form-group">
- <div class="col-md-4 col-md-push-2">
- <div>
- <button type="submit"
- class="btn btn-warning"
- value="Process">
-
- <span class="ladda-label">Send Notification</span>
- </button>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- }
- </section>
- </div>
In the above code, I have created a simple Razor AJAX form and unobtrusive form validation.
Step 8
Now, create "Scripts\custom-form.js"file and replace following code in it:
- $(document).ready(function () {
- $("#EmailNotifyformId").submit(function (event) {
- var dataString;
- event.preventDefault();
- event.stopImmediatePropagation();
- var action = $("#EmailNotifyformId").attr("action");
-
-
- dataString = new FormData($("#EmailNotifyformId").get(0));
- contentType = false;
- processData = false;
-
- $.ajax({
- type: "POST",
- url: action,
- data: dataString,
- dataType: "json",
- contentType: contentType,
- processData: processData,
- success: function (result) {
-
- onEmailNotifySuccess(result);
- },
- error: function (jqXHR, textStatus, errorThrown) {
-
- alert("fail");
- }
- });
-
- });
- });
-
- var onEmailNotifySuccess = function (result) {
- if (result.EnableError) {
-
- alert(result.ErrorMsg);
- }
- else if (result.EnableSuccess) {
-
- alert(result.SuccessMsg);
-
-
- $('#EmailNotifyformId').get(0).reset();
- }
- }
The above code is essential part of razor ajax form, I will not go into its details.
Step 9
Now, execute the project and you will be able to see the following:
Type recipient email address and press "Send Notification" button, you will see "The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at" error i.e.
There are two main reasons for the above error:
- I am using localhost and not SSL enabled certificate i.e. "https://".
- I am using Gmail account as source email address and Gmail account explicitly requires access permission for logins outside Gmail client.
Even if you enable SSL certificate, you will still see the error because of Gmail explicit permission settings. The above error happens only for Gmail not by other providers. Gmail will also send you an email about sign-in attempts as shown below:
So, in order to enable access permission for gmail account, perform the following steps:
- Login to your Gmail account from the web browser.
- Go to "https://myaccount.google.com/lesssecureapps" link.
- Turn "Allow less secure apps" property "ON".
As shown below i.e.
Now, execute the project and type recipient email address and press "Send Notification" button, you will see success message as shown below:
Check the recipient account to verify the notification message and your recipient has received the email notification as shown below:
Conclusion
In this article, we learned how to send an email notification to the recipient email address from our website. We leamed about SmtpClient library and different configuration settings in order to send the email notification. We saw SMTP protocol host types for different common email providers. You also learned to resolve the source Gmaill account sign-in issue outside the Gmail client and allow sign-in access to less secure apps for your source Gmail account.