feat: notification digests via SMTP
Adds a periodic inbox-summary email per opted-in user. SMTP is configured via appsettings (Smtp section); the digest is built from existing analytics (health score, top senders, recommendations) and sent by a new hourly DigestWorker, mirroring the GmailSyncWorker pattern. Frequency and send hour are configurable (Digest section). Backend: IEmailSender (SmtpEmailSender, MailKit), IDigestService, DigestWorker, new User.DigestEnabled/LastDigestSentUtc fields + migration, SettingsController for the per-user toggle and a send-now test endpoint, all scoped to the authenticated UserId. Frontend: SettingsApi + a bell/no-bell toggle button in the topbar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ using InboxIntel.Infrastructure.Cleanup;
|
||||
using InboxIntel.Infrastructure.Configuration;
|
||||
using InboxIntel.Infrastructure.Export;
|
||||
using InboxIntel.Infrastructure.Gmail;
|
||||
using InboxIntel.Infrastructure.Notifications;
|
||||
using InboxIntel.Infrastructure.Persistence;
|
||||
using InboxIntel.Infrastructure.Search;
|
||||
using InboxIntel.Infrastructure.Security;
|
||||
@@ -30,6 +31,8 @@ public static class DependencyInjection
|
||||
services.Configure<GoogleOAuthOptions>(config.GetSection(GoogleOAuthOptions.SectionName));
|
||||
services.Configure<GmailSyncOptions>(config.GetSection(GmailSyncOptions.SectionName));
|
||||
services.Configure<AiOptions>(config.GetSection(AiOptions.SectionName));
|
||||
services.Configure<SmtpOptions>(config.GetSection(SmtpOptions.SectionName));
|
||||
services.Configure<DigestOptions>(config.GetSection(DigestOptions.SectionName));
|
||||
|
||||
// Security
|
||||
services.AddSingleton<ITokenProtector, DataProtectionTokenProtector>();
|
||||
@@ -51,6 +54,11 @@ public static class DependencyInjection
|
||||
services.AddScoped<IUnsubscribeService, UnsubscribeService>();
|
||||
services.AddScoped<IExportService, ExportService>();
|
||||
|
||||
// Notifications (digest emails)
|
||||
services.AddScoped<IEmailSender, SmtpEmailSender>();
|
||||
services.AddScoped<IDigestService, DigestService>();
|
||||
services.AddHostedService<DigestWorker>();
|
||||
|
||||
// HTTP clients
|
||||
services.AddHttpClient("unsubscribe", c => c.Timeout = TimeSpan.FromSeconds(15));
|
||||
services.AddHttpClient("ollama");
|
||||
|
||||
Reference in New Issue
Block a user