private async Task SendAlertsForJobSet(IJobsDataProvider jobsProvider, JobsSet jobsSet, int?frequency, JobAlertSettings alertSettings, bool forceResend) { // No point sending alerts without links to the jobs if (alertSettings.JobAdvertBaseUrl == null) { _log.Error("JobAdvertBaseUrl not found - aborting"); return; } // We need somewhere to get the alerts from... var converter = new JobSearchQueryConverter(ConfigurationManager.AppSettings["TranslateObsoleteJobTypes"]?.ToUpperInvariant() == "TRUE"); var encoder = new JobAlertIdEncoder(converter); IJobAlertsRepository alertsRepo = new AzureTableStorageAlertsRepository(converter, ConfigurationManager.ConnectionStrings["JobAlerts.AzureStorage"].ConnectionString); // We need a way to send the alerts... var configuration = new ConfigurationServiceRegistry(); var emailService = ServiceContainer.LoadService <IEmailSender>(configuration); var sender = new JobAlertsByEmailSender(alertSettings, new HtmlJobAlertFormatter(alertSettings, encoder), emailService); // Get them, sort them and send them _log.Info($"Requesting jobs matching {jobsSet} with frequency {frequency} from Azure Storage"); var alerts = await alertsRepo.GetAlerts(new JobAlertsQuery() { Frequency = frequency, JobsSet = jobsSet }); var alertsGroupedByEmail = GroupAlertsByEmail(alerts); _log.Info($"{alerts.Count()} alerts found for {alertsGroupedByEmail.Count()} email addresses"); foreach (var alertsForAnEmail in alertsGroupedByEmail) { foreach (var alert in alertsForAnEmail) { var jobsSentForThisEmail = forceResend ? new List <int>() : await alertsRepo.GetJobsSentForEmail(alert.JobsSet, alert.Email); await LookupJobsForAlert(jobsProvider, alert, jobsSentForThisEmail); } } _log.Info("Sending alerts"); await sender.SendGroupedAlerts(alertsGroupedByEmail, alertsRepo); }