How to Send Emails and Reminders for Events in Blazor Scheduler | Syncfusion Blogs
Detailed Blog page Skeleton loader
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.

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; }
}

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; }
}

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);
}

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;
    }
}

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"
}

Note: In the previous settings, the Port number and the Hostname 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>();
}

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

@inject EmailScheduler.EmailServices.IEmailService EmailService

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]);
        }
    }

}

Now, the person scheduled for the event will receive email reminders.

Configuring reminder settings

Use the reminder setting to display the notification before the begining of an event. 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;
    }

}

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

Resource

To learn more, refer to the send emails and reminders for events in Blazor Scheduler demo.

Summary

This blog explained in detail how to send emails and reminders using 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 forumsDirect-Trac, or feedback portal. We are always happy to assist you!

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

Be the first to get updates

Sellakumar

Meet the Author

Sellakumar

Sellakumar is a Product Manager at Syncfusion. He has been a web developer since 2014 and working on custom control development. He is passionate about web technologies, who publishes articles to help web developers. Currently, he is exploring web application development using Blazor.