DEV Community

Cover image for How to Send Emails and Reminders for Events in Blazor Scheduler
Suresh Mohan for Syncfusion, Inc.

Posted on • Originally published at syncfusion.com on

How to Send Emails and Reminders for Events in Blazor Scheduler

Our Syncfusion Blazor Scheduler is a fully-featured calendar component that helps users manage their time efficiently. It facilitates easy resource scheduling, the rescheduling appointments of through editor pop-ups, drag and drop, and resizing actions.

The Blazor Scheduler also allows you to send emails and reminder notifications to each person involved in a project. In this blog, we will discuss how to configure the email and reminder settings in your Blazor Scheduler application.

Let’s get started!

Project setup

First, create a simple Scheduler in your Blazor server-side application. Refer to this Getting Started with Blazor Scheduler Component UG documentation for an introduction to configuring the common specifications.

Configuring email settings

Let’s configure the email setup in the project.

Step 1: Create a new folder in the project root directory with the name Models like in the screenshot.

Create a new folder in the project root directory with the name Models

Step 2: Create a class named EventModel inside the Models folder.

public class EventModel
{
    public int Id { get; set; }
    public string Subject { get; set; }
    public string Location { get; set; }
    public string Description { get; set; }
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    public string StartTimezone { get; set; }
    public string EndTimezone { get; set; }
    public bool? IsAllDay { get; set; }
    public bool? IsBlock { get; set; }
    public bool? IsReadonly { get; set; }
    public int? RecurrenceID { get; set; }
    public int? FollowingID { get; set; }
    public string RecurrenceRule { get; set; }
    public string RecurrenceException { get; set; }
    public int? EmployeeId { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Then, create a new folder in the project root directory and name it EmailServices.

Create a new folder in the project root directory and name it EmailServices

Step 4: Then, create a new class for EmailSettings inside the EmailServices folder. Refer to the following code example.

public class EmailSettings
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string DisplayName { get; set; }
    public string Host { get; set; }
    public int Port { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Create an interface for the IEmailService inside the EmailServices.

interface IEmailService
{
    Task<string> SendEmailAsync(string ToEmailName, string Subject, EventModel Data);
    Task<string> SendEmailAsync(List<string> ToEmailNames, string Subject, EventModel Data);
    bool IsValidEmail(string EmailName);
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Now, create the EmailService class inside the EmailServices folder and inherit it from the IEmailService interface.

public class EmailService : IEmailService
{
    private readonly EmailSettings _mailConfig;
    private static string _mailResponse;

    public EmailService(EmailSettings mailConfig)
    {
        _mailConfig = mailConfig;
    }

    public async Task<string> SendEmailAsync(string ToEmailName, string Subject, EventModel Data)
    {
        return await SendEmailAsync(new List<string>() { ToEmailName }, Subject, Data);
    }

    public async Task<string> SendEmailAsync(List<string> ToEmailName, string Subject, EventModel Data)
    {
        _mailResponse = string.Empty;

        using (SmtpClient smtpClient = new SmtpClient(_mailConfig.Host, _mailConfig.Port))
        {
            smtpClient.UseDefaultCredentials = true;
            smtpClient.Credentials = new NetworkCredential(_mailConfig.Username, _mailConfig.Password);
            smtpClient.EnableSsl = true;
            smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
            smtpClient.SendCompleted += new SendCompletedEventHandler((object sender, AsyncCompletedEventArgs e) => {
                    _mailResponse = (e.Error != null || e.Cancelled != false) ? "failure" : "success";
                });

            MailMessage message = new MailMessage
            {
                From = new MailAddress(_mailConfig.Username, _mailConfig.DisplayName),
                Subject = Subject,
                SubjectEncoding = Encoding.UTF8,
                BodyEncoding = Encoding.UTF8,
                HeadersEncoding = Encoding.UTF8,
                IsBodyHtml = true,
                Body = GetEmailContent(Subject, Data),
                Priority = MailPriority.High
            };
            foreach (string EmailName in ToEmailName)
            {
                message.To.Add(new MailAddress(EmailName));
            }

            await smtpClient.SendMailAsync(message);
        }

        return _mailResponse;
    }

    public bool IsValidEmail(string EmailName)
    {
        return new EmailAddressAttribute().IsValid(EmailName);
    }

    private string GetEmailContent(string Title, EventModel Data)
    {
        string HTMLBody = string.Empty;

            using (FileStream fs = File.Open(Directory.GetCurrentDirectory() + "/Email_Template.html", FileMode.Open, FileAccess.ReadWrite))
            {
                using (StreamReader sr = new StreamReader(fs))
                {
                    HTMLBody = sr.ReadToEnd();
                }
            }

            HTMLBody = HTMLBody.Replace("###EMAILTITLE###", Title);
            HTMLBody = HTMLBody.Replace("###EVENTSUBJECT###", Data.Subject ?? "(No Title)");
            HTMLBody = HTMLBody.Replace("###EVENTSTART###", Data.StartTime.ToString());
            HTMLBody = HTMLBody.Replace("###EVENTEND###", Data.EndTime.ToString());
            HTMLBody = HTMLBody.Replace("###EVENTLOCATION###", Data.Location ?? "NA");
            HTMLBody = HTMLBody.Replace("###EVENTDETAILS###", Data.Description ?? "NA");
            HTMLBody = HTMLBody.Replace("###CURRENTYEAR###", DateTime.Now.Year.ToString());

            return HTMLBody;
    }
}
Enter fullscreen mode Exit fullscreen mode

Note: We can also create our own email template in the project root directory under the name Email_Template.html.

Step 7: In the appsettings.json file, define the email settings-related credentials.

"EmailSettings": {
    "DisplayName": "Syncfusion Scheduler",
    "Username": "xxxxxxxxxxxxxxx@outlook.com",
    "Password": "xxxxxxxxxx",
    "Port": 587,
    "Host": "smtp.office365.com"
}
Enter fullscreen mode Exit fullscreen mode

Note: In the previous settings, the Port number and the _Host_name will vary based on the email domain.

Step 8: In the Startup.cs file, add our EmailService in the ConfigureService method.

public void ConfigureServices(IServiceCollection services)
{
  . . . . . . . . . . . . . 
  . . . . . . . . . . . . .
  services.AddSingleton(Configuration.GetSection("EmailSettings").Get<EmailSettings>());
  services.AddScoped<IEmailService, EmailService>();
}
Enter fullscreen mode Exit fullscreen mode

Now, your project has been successfully configured with the EmailService.

Step 9: Then, in the Index.razor file, inject the email service like in the following code.

@inject EmailScheduler.EmailServices.IEmailService EmailService
Enter fullscreen mode Exit fullscreen mode

Now, use this service to send emails to the appropriate person when an event CRUD action happens.

Here is the code to send the email to a person when a new event is scheduled to them in the Scheduler.

@page "/"
@inject EmailScheduler.EmailServices.IEmailService EmailService

@using EmailScheduler.Models
@using Syncfusion.Blazor.Schedule

<div class="control-container">
    <div class="schedule-control">
        <SfSchedule @ref="ScheduleRef" TValue="EventModel" Height="500px">
            <ScheduleGroup EnableCompactView="false" Resources="@GroupData"></ScheduleGroup>
            <ScheduleResources>
                <ScheduleResource TItem="ResourceModel" TValue="int[]" DataSource="@ResourceData" Field="EmployeeId" Title="Employee Name" Name="Employees" TextField="EmployeeName" IdField="EmployeeId" ColorField="EmployeeColor" AllowMultiple="true"></ScheduleResource>
            </ScheduleResources>
            <ScheduleEventSettings DataSource="@DataSource"></ScheduleEventSettings>
            <ScheduleEvents TValue="EventModel" ActionCompleted="OnActionCompleted"></ScheduleEvents>
        </SfSchedule>
    </div>
</div>

@code{
    SfSchedule<EventModel> ScheduleRef;

    private class ResourceModel
    {
        public string EmployeeName { get; set; }
        public int EmployeeId { get; set; }
        public string EmployeeColor { get; set; }
        public string EmployeeEmail { get; set; }
    }

    private string[] GroupData { get; set; } = new string[] { "Employees" };
    private List<ResourceModel> ResourceData { get; set; } = new List<ResourceModel> {
        new ResourceModel { EmployeeId = 1, EmployeeName = "Employee 1", EmployeeColor = "#EA7A57", EmployeeEmail = "xxxxxxxxxxxxxxx@outlook.com" },
        new ResourceModel { EmployeeId = 2, EmployeeName = "Employee 2", EmployeeColor = "#357cd2", EmployeeEmail = "xxxxxxxxxxxxxxx@gmail.com" },
        new ResourceModel { EmployeeId = 3, EmployeeName = "Employee 3", EmployeeColor = "#7fa900", EmployeeEmail = "xxxxxxxxxxxxxxx@yahoo.com" }
    };
    private List<EventModel> DataSource = GenerateEvents();

    private static List<EventModel> GenerateEvents()
    {
        DateTime date1 = DateTime.Now;
        DateTime startDate = new DateTime(date1.Year, date1.Month, date1.Day, date1.Hour, date1.Minute, 0).AddMinutes(6);
        DateTime endDate = new DateTime(startDate.Ticks).AddHours(2);
        List<EventModel> collections = new List<EventModel>() {
            new EventModel { Id = 1, Subject = "Testing", StartTime = startDate, EndTime = endDate, EmployeeId = 1 },
            new EventModel { Id = 2, Subject = "Meeting", StartTime = startDate, EndTime = endDate, EmployeeId = 2 },
            new EventModel { Id = 3, Subject = "Conference", StartTime = startDate, EndTime = endDate, EmployeeId = 3 }
        };
        return collections;
    }

    private async void OnActionCompleted(ActionEventArgs<EventModel> args)
    {
        if (args.ActionType == ActionType.EventCreate || args.ActionType == ActionType.EventChange || args.ActionType == ActionType.EventRemove)
        {
            List<EventModel> added = args.AddedRecords ?? new List<EventModel>();
            List<EventModel> changed = args.ChangedRecords ?? new List<EventModel>();
            List<EventModel> deleted = args.DeletedRecords ?? new List<EventModel>();
            List<EventModel> datas = added.Concat(changed).Concat(deleted).ToList();
            List<string> toEmail = new List<string>();
            foreach (EventModel data in datas)
            {
                string email = ResourceData.Where(e => e.EmployeeId == data.EmployeeId).FirstOrDefault().EmployeeEmail;
                if (EmailService.IsValidEmail(email))
                {
                    toEmail.Add(email);
                }
            }
            toEmail = toEmail.Distinct().ToList();
            string Title = string.Empty;
            switch (args.ActionType)
            {
                case ActionType.EventCreate:
                    Title = "New Event Scheduled";
                    break;
                case ActionType.EventChange:
                    Title = "Scheduled Event Updated";
                    break;
                case ActionType.EventRemove:
                    Title = "Scheduled Event Removed";
                    break;
            }
            await EmailService.SendEmailAsync(toEmail, Title, datas[0]);
        }
    }

}
Enter fullscreen mode Exit fullscreen mode

Now, the email will be sent successfully to the person scheduled for the event.

Configuring reminder settings

Reminder settings are used to display notifications before an event begins. We can set different intervals between notifications and events’ beginning times.

Using the Syncfusion Blazor Toast component, we can display the event reminders. The complete code of reminder settings is as follows.

@page "/"

@using EmailScheduler.Models
@using Syncfusion.Blazor.Notifications
@using Syncfusion.Blazor.Schedule
@using System.Timers

<div class="control-container">
    <div class="toast-control">
        <SfToast @ref="ToastRef" CssClass="e-schedule-reminder e-toast-info" NewestOnTop="true" ShowCloseButton="true" Target=".e-schedule" Timeout="10000">
            <ToastAnimationSettings>
                <ToastShowAnimationSettings Effect="ToastEffect.SlideRightIn"></ToastShowAnimationSettings>
                <ToastHideAnimationSettings Effect="ToastEffect.SlideRightOut"></ToastHideAnimationSettings>
            </ToastAnimationSettings>
            <ToastPosition X="Right" Y="Top"></ToastPosition>
            <ToastTemplates>
                <Template>
                    <div class="e-toast-template e-toast-info">
                        <div class="e-custom-toast">
                            <div class="e-toast-icon e-icons e-schedule-meeting-icon"></div>
                            <div class="e-avatar e-avatar-xsmall e-avatar-circle e-toast-avatar">
                                <img class="image" src="/images/status/@(EventData.EmployeeId).png" alt="avatar" />
                            </div>
                        </div>
                        <div class="e-toast-message">
                            <div class="e-toast-title">@EventData.Subject</div>
                            <div class="e-toast-content">@(EventData.StartTime.ToShortTimeString() + " - " + EventData.EndTime.ToShortTimeString())</div>
                        </div>
                    </div>
                </Template>
            </ToastTemplates>
            <ToastEvents Created="OnToastCreated"></ToastEvents>
        </SfToast>
    </div>
    <div class="schedule-control">
        <SfSchedule @ref="ScheduleRef" TValue="EventModel" Height="500px">
            <ScheduleGroup EnableCompactView="false" Resources="@GroupData"></ScheduleGroup>
            <ScheduleResources>
                <ScheduleResource TItem="ResourceModel" TValue="int[]" DataSource="@ResourceData" Field="EmployeeId" Title="Employee Name" Name="Employees" TextField="EmployeeName" IdField="EmployeeId" ColorField="EmployeeColor" AllowMultiple="true"></ScheduleResource>
            </ScheduleResources>
            <ScheduleEventSettings DataSource="@DataSource"></ScheduleEventSettings>
        </SfSchedule>
    </div>
</div>

<style>
    .e-toast .e-schedule-reminder .e-toast-template {
        display: flex;
    }

    .e-toast .e-schedule-reminder .e-custom-toast {
        display: inline-grid;
    }

    .e-toast .e-schedule-reminder .e-schedule-meeting-icon::before {
        content: "\e763";
        font-size: 20px;
    }

    .e-toast .e-schedule-reminder .e-toast-avatar {
        margin-top: 14px;
    }
</style>

@code{
    SfToast ToastRef;
    SfSchedule<EventModel> ScheduleRef;

    private class ResourceModel
    {
        public string EmployeeName { get; set; }
        public int EmployeeId { get; set; }
        public string EmployeeColor { get; set; }
        public string EmployeeEmail { get; set; }
    }

    private EventModel EventData { get; set; }
    private string[] GroupData { get; set; } = new string[] { "Employees" };
    private List<ResourceModel> ResourceData { get; set; } = new List<ResourceModel> {
        new ResourceModel { EmployeeId = 1, EmployeeName = "Employee 1", EmployeeColor = "#EA7A57", EmployeeEmail = "xxxxxxxxxxxxxxx@outlook.com" },
        new ResourceModel { EmployeeId = 2, EmployeeName = "Employee 2", EmployeeColor = "#357cd2", EmployeeEmail = "xxxxxxxxxxxxxxx@gmail.com" },
        new ResourceModel { EmployeeId = 3, EmployeeName = "Employee 3", EmployeeColor = "#7fa900", EmployeeEmail = "xxxxxxxxxxxxxxx@yahoo.com" }
    };
    private List<EventModel> DataSource = GenerateEvents();

    private void OnToastCreated()
    {
        Timer timer = new Timer(60000);
        timer.Elapsed += new ElapsedEventHandler(async (object sender, ElapsedEventArgs e) =>
        {
            List<EventModel> eventDatas = ScheduleRef.GetCurrentViewEvents();
            int AlertBeforeMinutes = 5;
            DateTime CurrentTime = DateFormat(DateTime.Now);
            foreach (EventModel eventData in eventDatas)
            {
                DateTime StartTime = DateFormat(eventData.StartTime);
                if (DateTime.Compare(CurrentTime, StartTime.AddMinutes(-AlertBeforeMinutes)) == 0)
                {
                    EventData = eventData;
                    await InvokeAsync(async () => await ToastRef.Show());
                }
            }
        });
        timer.Enabled = true;
    }

    private DateTime DateFormat(DateTime date)
    {
        return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, 0);
    }

    private static List<EventModel> GenerateEvents()
    {
        DateTime date1 = DateTime.Now;
        DateTime startDate = new DateTime(date1.Year, date1.Month, date1.Day, date1.Hour, date1.Minute, 0).AddMinutes(6);
        DateTime endDate = new DateTime(startDate.Ticks).AddHours(2);
        List<EventModel> collections = new List<EventModel>() {
            new EventModel { Id = 1, Subject = "Testing", StartTime = startDate, EndTime = endDate, EmployeeId = 1 },
            new EventModel { Id = 2, Subject = "Meeting", StartTime = startDate, EndTime = endDate, EmployeeId = 2 },
            new EventModel { Id = 3, Subject = "Conference", StartTime = startDate, EndTime = endDate, EmployeeId = 3 },
        };
        return collections;
    }

}
Enter fullscreen mode Exit fullscreen mode

Now, the reminder notification will be displayed to the appropriate person 5 minutes before the event begins.

GitHub reference

You can check out the complete working example of this Blazor server application on this GitHub repository.

Summary

This blog explained in detail how to configure email service and reminder settings in the Syncfusion Blazor Scheduler. With this, each and every person involved in a project will be informed of the events assigned to them and also get reminder notifications about their tasks. This will enhance their productivity.

So, try these features out and leave your feedback in the comments section below.

Syncfusion Essential Studio for Blazor offers 65+ high-performance, lightweight, and responsive UI components for the web, including file-format libraries, in a single package. Please take a look at our live demos in our sample browser for a hands-on experience.

For existing customers, the latest version is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out the available features. You can also try our samples from this GitHub location.

If you have questions, you can contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!

If you like this post, we think you will also like the following:

Top comments (0)