ASP.NET CORE: Sending Email with Gmail and Homtail Account using ASP.NET Core services

Standard

Sending email from any SMTP server from ASP.NET CORE application is pretty easy, but the flow of command is slight different in core environment.

Gmail SMTP server address is smtp.gmail.com. It requires implicit SSL or explicit SSL (TLS) connection, and you should use your Gmail email address as the user name for ESMTP authentication.

So basically we will read email smtp address, port, username and password from appsettings.json, then will inject these config to email service class, in the end we will inject email service class to controller and consumer email send operation.

Step 1: Define email specific information in appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": ""
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "EmailSettings": {
    "PrimaryDomain": "smtp.gmail.com",
    "PrimaryPort": "587",
    "SecondayDomain": "smtp.live.com",
    "SecondaryPort": "587",
    "UsernameEmail": "emailId@gmail.com",
    "UsernamePassword": "emailPassword",
    "FromEmail": "fromEmail",
    "ToEmail": "toEmail",
    "CcEmail": "ccEmail"
  }
}

SmtpServer: The name of the server that will be used to send the emails.

SmtpPort: The port, which the server will use to send SMTP transactions (emails).

EnableSsl: True, if the server should use SSL (Secure Socket Layer) encryption.

Smtp Server Address and Port #

Server Name SMTP Address Port SSL
Yahoo! smtp.mail.yahoo.com 587 Yes
GMail smtp.gmail.com 587 Yes
Hotmail smtp.live.com 587 Yes

Step 2: Create a class to encapsulate EmailSettings properties from appsettings.json

public class EmailSettings
    {
        public String PrimaryDomain { get; set; }

        public int PrimaryPort { get; set; }

        public String SecondayDomain { get; set; }

        public int SecondaryPort { get; set; }

        public String UsernameEmail { get; set; }

        public String UsernamePassword { get; set; }

        public String FromEmail { get; set; }

        public String ToEmail { get; set; }

        public String CcEmail { get; set; }
    }

Step 3: Register class in startup.cs for DI purposes

services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));

Step 4: Create an Email sender interface

public interface IEmailSender
{
    Task SendEmailAsync(string email, string subject, string message);
}

Step 5: Create a message service class which will implement this interface

Inject EmailSettings class in message service using options pattern, so that email configuration defined in appsettings.json is available in this service.

We will use SmtpClient class to allow applications to send e-mail by using the Simple Mail Transfer Protocol (SMTP).

public class AuthMessageSender : IEmailSender, ISmsSender
    {
        public AuthMessageSender(IOptions<EmailSettings> emailSettings)
        {
            _emailSettings = emailSettings.Value;
        }

        public EmailSettings _emailSettings { get; }

        public Task SendEmailAsync(string email, string subject, string message)
        {

            Execute (email, subject, message).Wait();
            return Task.FromResult(0);
        }

        public async Task Execute(string email, string subject, string message)
        {
          try
          {
            string toEmail = string.IsNullOrEmpty(email) 
                             ? _emailSettings.ToEmail 
                             : email;
            MailMessage mail = new MailMessage()
            {
                From = new MailAddress(_emailSettings.UsernameEmail, "Muhammad Hassan Tariq")
            };
            mail.To.Add(new MailAddress(toEmail));
            mail.CC.Add(new MailAddress(_emailSettings.CcEmail));

            mail.Subject = "Personal Management System - " + subject;
            mail.Body = message;
            mail.IsBodyHtml = true;
            mail.Priority = MailPriority.High;

            using (SmtpClient smtp = new SmtpClient(_emailSettings.SecondayDomain, _emailSettings.SecondaryPort))
            {
                smtp.Credentials = new NetworkCredential(_emailSettings.UsernameEmail, _emailSettings.UsernamePassword);
                smtp.EnableSsl = true;
                await smtp.SendMailAsync(mail);
            }
          }
          catch(Exception ex)
          {
             //do something here
          }
        }
    }

*exception handling is left for you to implement 🙂

  • You can attach one or several files:
mail.Attachments.Add(new Attachment(Server.MapPath("~/myimage.jpg")));
  • You can send to more than one person at the same time
mail.To.Add("test@email.com");
mail.To.Add("test2@email.com");
  • You can set a name for the sender
mail.From = new MailAddress("test@email.com", "Hello");
  • You can send HTML e-mails, instead of the default plaintext mails
mail.IsBodyHtml = true;
mail.Body = "Testing <b>123!</b>";
  • You can use the CC and BCC fields
mail.CC.Add("test@email.com");
mail.Bcc.Add("test2@email.com");
  • You can set the priority of an e-mail
mail.Priority = MailPriority.High;

Step 6: Register email sender service in startup.cs, so that it can be injected in controllers

services.AddTransient<IEmailSender, AuthMessageSender>();

Step 7: Controller code (consumer)

Inject email sender service in controller constructor and then invoke SendEmailAsync method of it

public class TestController : Controller
    {
        private readonly IEmailSender _emailSender;

        public AccountController(IEmailSender emailSender)
        {
            _emailSender = emailSender;
        }
        
        public async Task TestAction()
        {
           await _emailSender.SendEmailAsync("test@gmail.com", "subject",
                        $"Enter email body here");
        }
    }

Note:

Google may block sign in attempts from some apps or devices that do not use modern security standards. Since these apps and devices are easier to break into, blocking them helps keep your account safer.

Please make sure, in Gmail settings of your account, enable access for less secure apps to avoid below error:

The SMTP server requires a secure connection or the client was not 
authenticated. The server response was: 5.5.1 Authentication Required?

Advertisements

ASP.NET: Store Email Template in .NET

Standard

Simple and Easy to edit way to store email templates in your .net project is string email body in html file.

Step 1: Create a HTML mail message

2016-10-04-16_04_18-_c__users_hassan-muhammad_desktop_new-14-html-notepad

Step 1(a): You can introduce as many as variable in HTML template by any character scheme (@PARAMETER@ or #PARAMETER# or $$PARAMETER$$). Replace all names/variables with things like #VaraibleName#
The confirmation number is: <b>#confirmNumber#</b>
Step 2: Right click on web project and select Properties from right click menu

2016-10-04-16_08_58-recruiting-microsoft-visual-studio-administrator

Step 3: Select Resources tab from left, choose Add Resource, select Add Existing File and choose appropriate html file

2016-10-04-16_24_57-recruiting-microsoft-visual-studio-administrator

Step 4: File will be visible in Resources display pan

2016-10-04-16_26_31-recruiting-microsoft-visual-studio-administrator

Step 5: For Server side C# code

You can refer to HTML email template from Properties.Resources.EmailTemplate. You can use it as a string. Replace the #PARAMETER# text with the actual values.

private void SendConfirmationEmail(string email, string confirmNumber)
{
    var emailBody = Properties.Resources.EmailTemplate.Replace("#confirmNumber#", confirmNumber);
    MailMessage message =
        new MailMessage
        {
            From =
            new MailAddress("Sender Email Address"),
            Subject = "Email Subject Content",
            Body = string.Format(emailBody),
            IsBodyHtml = true
        };
 
    message.To.Add(new MailAddress(email));
    SmtpClient client = new SmtpClient("11.111.111.11");
    client.Send(message);
}

Custom Prompt with DatePicker directive in AngularJS

Standard

Introduction

Due to design constraints there is a slight possibility, you are advised not to use Angular UI model in order to display prompt box in your angular web application, however below code help you to achieve custom prompt with dataepicker intgration in it with basic validation. its a custom prompt, you may change it to confirm box as per need.

Using the code

<body ng-app="popup">
        <div ng-controller="popupController">
            <input type="button" value="Show Popup" ng-click="isPopupVisble()" />
            <div ng-show="showPopup">
                <div class="alertBg">
                    <div class="alertPlaceholder ">
                        <div class="alertIcon">
                            <img src="Content/infoiconlarge.jpg" />
                        </div>
                        <h3>Are you sure?</h3>
                        <div class="inlineError" ng-show="errorMessage"> 
                           Please provide an end date. 
                        </div>
                        <input type="text" datepicker class="textBoxStyle datetimePicker" 
                               placeholder="Effective End Date" data-ng-model="EndDate" />
                        <div>
                            <button id="btnOkRemove" class="confirm" tabindex="2" 
                                       data-ng-click="deleteRecord()">OK</button>
                            <button id="btnCanceRemove" class="cancel" tabindex="2" 
                                        data-ng-click="hidePrompt()">Cancel</button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
//Module
    var sample = angular.module('popup', ['ngRoute']);

    sample.directive("datepicker", function() {
        return {
            restrict: "A",
            require: "ngModel",
            link: function(scope, elem, attrs, ngModelCtrl) {
                var updateModel = function(dateText) {
                    scope.$apply(function() {
                        ngModelCtrl.$setViewValue(dateText);
                    });
                };
                var options = {
                    dateFormat: "mm/dd/yy",
                    onSelect: function(dateText) {
                        updateModel(dateText);
                    }
                };
                elem.datepicker(options);
            }
        }
    });

//Controller
    sample.controller('popupController', function ($scope) {
        $scope.showPopup = false;
        $scope.errorMessage = false;

        $scope.isPopupVisble = function () {
            $scope.showPopup = true;
        };
        $scope.hidePrompt = function () {
            $scope.EndDate = "";
            $scope.errorMessage = false;
            $scope.showPopup = false;
        };
        $scope.deleteRecord = function() {
            var endDate = $scope.EndDate != null ? new Date($scope.EndDate) : "Invalid Date";
            if (endDate == "Invalid Date") {
                $scope.errorMessage = true;
                return;
            }
            $scope.hidePrompt();
        };
    });

Points of Interest

Basic validation has been implemented, you may extend it as per need.  Value of selected date will be available in scope within model name ‘EndDate’

For the complete source code, please see https://github.com/m-hassan-tariq/PromptWithDatePickerDirectiveAngularJS
UI and UX contributed by
Muhammad Zain Ansari
adnanansari86pk@gmail.com

Email Input Tokenizer – AngularJS Directive

Standard

Introduction

While implementing Single Page Application through WebAPI and AngularJS, You came across number of times to use filters and directive in order to meet requirements specified by clients, below code snippet, tokenize input and display them in separate block within a specific placeholder, however it checks the input is valid email address first  and then the input token is not repetitive within same placeholder,

Using the code

<body ng-app="tokenizer">
    <div ng-controller="tokenizerController">
        <tag-input taglist='email' placeholder="Emails"></tag-input>  
    </div>
</body>
var sample = angular.module('tokenizer', ['ngRoute']);


sample.controller('tokenizerController', function ($scope) {
       
   });

   sample.directive('tagInput', function () {
       return {
           restrict: 'E',
           scope: {
               inputTags: '=taglist',
               autocomplete: '=autocomplete'
           },
           link: function ($scope, element, attrs) {
               $scope.defaultWidth = 200;
               $scope.tagText = '';
               $scope.placeholder = attrs.placeholder;
               $scope.tagArray = function () {
                   if ($scope.inputTags === undefined) {
                       return [];
                   }
                   return $scope.inputTags.split(',').filter(function (tag) {
                       return tag !== "";
                   });
               };
               $scope.addTag = function () {
                   var EMAIL_REGEXP = /^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/;
                   var tagArray;
                   if ($scope.tagText.length === 0) {
                       return;
                   }
                   if (!EMAIL_REGEXP.test($scope.tagText)) {
                       return $scope.tagText = "";
                   }
                   tagArray = $scope.tagArray();
                   if (!(tagArray.indexOf($scope.tagText) >= 0)) {
                       tagArray.push($scope.tagText);
                       $scope.inputTags = tagArray.join(',');
                   }
                   return $scope.tagText = "";
               };
               $scope.deleteTag = function (key) {
                   var tagArray;
                   tagArray = $scope.tagArray();
                   if (tagArray.length > 0 && $scope.tagText.length === 0 && key === undefined) {
                       tagArray.pop();
                   } else {
                       if (key !== undefined) {
                           tagArray.splice(key, 1);
                       }
                   }
                   return $scope.inputTags = tagArray.join(',');
               };
               $scope.$watch('tagText', function (newVal, oldVal) {
                   var tempEl;
                   if (!(newVal === oldVal && newVal === undefined)) {
                       tempEl = $("<span>" + newVal + "</span>").appendTo("body");
                       $scope.inputWidth = tempEl.width() + 5;
                       if ($scope.inputWidth < $scope.defaultWidth) {
                           $scope.inputWidth = $scope.defaultWidth;
                       }
                       return tempEl.remove();
                   }
               });
               element.bind("keydown", function (e) {
                   var key;
                   key = e.which;
                   if (key === 9 || key === 13) {
                       e.preventDefault();
                   }
                   if (key === 8) {
                       return $scope.$apply('deleteTag()');
                   }
               });
               return element.bind("keyup", function (e) {
                   var key;
                   key = e.which;
                   if (key === 9 || key === 13 || key === 188) {
                       e.preventDefault();
                       return $scope.$apply('addTag()');
                   }
               });
           },
           template: "<div class='tag-input-ctn'><div class='input-tag' data-ng-repeat=\"tag in tagArray()\">{{tag}}<div class='delete-tag' data-ng-click='deleteTag($index)'>&times;</div></div><input type='text' data-ng-style='{width: inputWidth}' data-ng-model='tagText' placeholder='{{placeholder}}'/></div>"
       };
   });

Points of Interest

emailtoken

For complete source code:

https://github.com/m-hassan-tariq/EmailInputTokenizerAngularJSDirective