Automatic Reminders - Code

C#

ReminderService.cs

namespace BlazorBirthdayReminders.Data
{
    using Dapper;
    using Microsoft.Data.SqlClient;
    using System.Data;

    using MailKit.Net.Smtp;
    using MailKit.Security;
    using Microsoft.Extensions.Configuration;
    using MimeKit;
    using MimeKit.Text;

    public interface IReminderService
    {
        public void SendReminders() { }
    }

    public class ReminderService : IReminderService
    {
        // Database connection
        private readonly IConfiguration _configuration;
        public ReminderService(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public string connectionId = "Default";

        private List<Person>? birthdaypeople;

        public async Task SendReminders()
        {
            string? SendTo;
            string? EmailSubject;
            string? EmailBody;

            for (int daysNotice = 7; daysNotice < 22; daysNotice = daysNotice + 7)
            {
                var parameters = new DynamicParameters();
                parameters.Add("@DaysToNextBirthday", daysNotice, DbType.Int32);
                IEnumerable<Person> people;
                using IDbConnection conn = new SqlConnection(_configuration.GetConnectionString(connectionId));
                {
                    people = await conn.QueryAsync<Person>("spPerson_GetByDaysToNextBirthday", parameters, commandType: CommandType.StoredProcedure);
                }

                birthdaypeople = people.ToList(); //Convert from IEnumerable to List

                foreach (var person in birthdaypeople)
                {
                    SendTo = person.PersonSendReminderTo;
                    EmailSubject = "It's " + person.PersonFullName + "'s Birthday!";
                    EmailBody = "<p>Hello</p>";
                    if (daysNotice == 21)
                    {
                        EmailBody = EmailBody + "<p>A bit of warning that it's ";
                    }
                    else if (daysNotice == 14)
                    {
                        EmailBody = EmailBody + "<p>Don't forget, it's ";
                    }
                    else
                    {
                        EmailBody = EmailBody + "<p>Better get cracking, it's only " + daysNotice + "days until ";
                    }

                    EmailBody = EmailBody + person.PersonFirstName + "'s birthday on " + person.NextBirthday.ToString("dd/MM/yyyy") + ".</p>";
                    if (person.AgeNextBirthday < 21)
                    {
                        EmailBody = EmailBody + "<p>" + person.PersonFirstName + " will be " + person.AgeNextBirthday + ".</p>";
                    }
                    EmailBody = EmailBody + "<p>Chris <br/>";
                    EmailBody = EmailBody + "Chris's automated Birthday Reminder Service<p>";

                    // Get settings from appsettings
                    var SmtpHost = _configuration["SmtpHost"];
                    var SmtpPort = _configuration["SmtpPort"];
                    var SmtpUserFriendlyName = _configuration["SmtpUserFriendlyName"];
                    var SmtpUserEmailAddress = _configuration["SmtpUserEmailAddress"];
                    var SmtpPass = _configuration["SmtpPass"];
                    // create message
                    var email = new MimeMessage();
                    email.From.Add(new MailboxAddress(SmtpUserFriendlyName, SmtpUserEmailAddress));
                    email.To.Add(new MailboxAddress(SendTo, SendTo));
                    email.Subject = EmailSubject;
                    email.Body = new TextPart(TextFormat.Html) { Text = EmailBody };

                    // send email
                    using var smtp = new SmtpClient();
                    {
                        smtp.Connect(SmtpHost, Int32.Parse(SmtpPort), SecureSocketOptions.StartTls);
                        smtp.Authenticate(SmtpUserEmailAddress, SmtpPass);
                        smtp.Send(email);
                        smtp.Disconnect(true);
                        smtp.Dispose();
                    }
                }
            }
        }
    }
}

Program.cs

using BlazorBirthdayReminders.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Syncfusion.Blazor;
using Hangfire;
using Hangfire.SqlServer;


var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();

builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddScoped<IPersonService, PersonService>();
//builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddTransient<IEmailService, EmailService>();           //Scoped didn't seem to work. Singleton did work.
builder.Services.AddSingleton<IReminderService, ReminderService>();

builder.Services.AddSyncfusionBlazor(options => { options.IgnoreScriptIsolation = true; });

builder.Services.AddHangfire(x => x
    .SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
    .UseSimpleAssemblyNameTypeSerializer()
    .UseRecommendedSerializerSettings()
    .UseSqlServerStorage(builder.Configuration.GetConnectionString("Default"), new SqlServerStorageOptions
    {
        CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
        SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
        QueuePollInterval = TimeSpan.Zero,
        UseRecommendedIsolationLevel = true,
        DisableGlobalLocks = true
    }));

builder.Services.AddHangfireServer();


var app = builder.Build();

///Register Syncfusion license
var SyncfusionLicenceKey = builder.Configuration["SyncfusionLicenceKey"];
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(SyncfusionLicenceKey);

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.UseHangfireDashboard("/dashboard");

//IEmailService EmailService = app.Services.GetRequiredService<IEmailService>();      //Needed for items below

//BackgroundJob.Enqueue(() => EmailService.Send("christopherbell@blazorcode.uk",
//    "SUBJECT - The program has started",
//    "This is the body of the email.  This is the email to say the program has started"));

//BackgroundJob.Schedule(() => EmailService.Send("christopherbell@blazorcode.uk",
//    "This is sent after a minute"
//    , "Welcome - This was sent one minute after starting"),
//    TimeSpan.FromMinutes(1));

//RecurringJob.AddOrUpdate(
//    "Run every 5 minutes", () => EmailService.Send("christopherbell@blazorcode.uk",
//     "Recurring Email every 5 minutes",
//     "Another 5 minutes ticks by...."),
//    "*/5 * * * *");

//RecurringJob.AddOrUpdate(
//    "Run every day at 10:57", () => EmailService.Send("christopherbell@blazorcode.uk",
//     "Recurring Email every day at 10:57",
//     "This is the body of the email"),
//     "57 10 * * *");

IReminderService ReminderService = app.Services.GetRequiredService<IReminderService>();      //Needed for items below
RecurringJob.AddOrUpdate(
    "Daily Birthday Reminder", () => ReminderService.SendReminders(),
    "35 16 * * *", TimeZoneInfo.Local);

app.Run();