Skip to content

Notifications — Multi-Channel Email, SMS & Push Engine

Granit.Notifications is a multi-channel notification engine built on a fan-out pattern. A single INotificationPublisher.PublishAsync() call fans out to every registered channel (InApp, Email, SMS, WhatsApp, Mobile Push, SignalR, SSE, Web Push, Zulip) after filtering through user preferences. Delivery attempts are recorded in an immutable audit trail (ISO 27001). By default, notifications dispatch via an in-process Channel<T> — add Granit.Notifications.Wolverine for durable outbox-backed dispatch with exponential backoff retry.

Channel packages (Email, Sms, MobilePush, WhatsApp, …) define the capability contracts; provider packages sit at the top level and implement one or more capabilities as Keyed Services. Multi-capability providers (AwsSns, AzureCommunicationServices, Brevo, Twilio) register each capability only when its configuration section exists — an SMS-only host never wires the push sender.

  • DirectoryGranit.Notifications/ Core: fan-out engine, InApp channel, definitions, entity tracking
    • Granit.Notifications.EntityFrameworkCore EF Core persistence (all stores)
    • Granit.Notifications.Endpoints Minimal API REST endpoints
    • Granit.Notifications.Wolverine Durable outbox dispatch via IMessageBus
    • Granit.Notifications.Privacy GDPR export/deletion satellite (notifications data)
    • Granit.Notifications.Email Email channel abstraction (Keyed Services)
    • Granit.Notifications.Sms SMS channel abstraction (Keyed Services)
    • Granit.Notifications.WhatsApp WhatsApp Business API channel
    • DirectoryGranit.Notifications.MobilePush/ Mobile push abstraction + token store
      • Granit.Notifications.MobilePush.Privacy GDPR export/deletion satellite (push tokens)
    • Granit.Notifications.SignalR Real-time SignalR channel + Redis backplane
    • DirectoryGranit.Notifications.WebPush/ W3C Web Push (VAPID, RFC 8030)
      • Granit.Notifications.WebPush.Privacy GDPR export/deletion satellite (subscriptions)
    • DirectoryGranit.Notifications.Sse/ Server-Sent Events channel (.NET 10)
      • Granit.Notifications.Sse.StackExchangeRedis Redis pub/sub backplane for multi-replica SSE
    • Granit.Notifications.Smtp MailKit SMTP provider (Email)
    • Granit.Notifications.AwsSes AWS SES provider (Email)
    • Granit.Notifications.Scaleway Scaleway TEM provider (Email)
    • Granit.Notifications.SendGrid SendGrid provider (Email)
    • Granit.Notifications.AzureCommunicationServices Azure Communication Services (Email + SMS)
    • Granit.Notifications.AwsSns AWS SNS (SMS + Mobile Push)
    • Granit.Notifications.Brevo Unified Brevo provider (Email + SMS + WhatsApp)
    • Granit.Notifications.Twilio Twilio provider (SMS + WhatsApp)
    • Granit.Notifications.GoogleFcm Firebase Cloud Messaging provider (Mobile Push)
    • Granit.Notifications.AzureNotificationHubs Azure Notification Hubs provider (Mobile Push)
    • Granit.Notifications.Zulip Zulip chat integration
PackageRoleDepends on
Granit.NotificationsFan-out engine, InApp channel, definitions, entity trackingGranit.Guids, Granit.Timing, Granit.QueryEngine
Granit.Notifications.EntityFrameworkCoreEF Core stores (all entities + mobile push tokens)Granit.Notifications, Granit.Notifications.MobilePush, Granit.Persistence
Granit.Notifications.EndpointsMinimal API endpoints (inbox, preferences, subscriptions, followers)Granit.Notifications, Granit.Notifications.MobilePush, Granit.Validation, Granit.Http.ApiDocumentation
Granit.Notifications.WolverineDurable outbox-backed dispatch via IMessageBusGranit.Notifications, Granit.Wolverine
Granit.Notifications.PrivacyGDPR export/deletion satellite for notifications dataGranit.Notifications, Granit.Privacy.BlobStorage
Granit.Notifications.EmailEmail channel abstraction, Keyed Services resolutionGranit.Notifications
Granit.Notifications.SmsSMS channel abstraction, Keyed Services resolutionGranit.Notifications
Granit.Notifications.WhatsAppWhatsApp Business API channelGranit.Notifications
Granit.Notifications.MobilePushMobile push abstraction + device token storeGranit.Notifications
Granit.Notifications.MobilePush.PrivacyGDPR export/deletion satellite for push device tokens (masked)Granit.Notifications.MobilePush, Granit.Privacy.BlobStorage
Granit.Notifications.SmtpMailKit SMTP provider (Keyed Service "Smtp")Granit.Notifications.Email
Granit.Notifications.AwsSesAWS SES email provider (Keyed Service "AwsSes")Granit.Notifications.Email
Granit.Notifications.ScalewayScaleway TEM email provider (Keyed Service "Scaleway")Granit.Notifications.Email
Granit.Notifications.SendGridSendGrid email provider (Keyed Service "SendGrid")Granit.Notifications.Email
Granit.Notifications.AzureCommunicationServicesAzure Communication Services provider — Email + SMS, each capability activated by its config section (Keyed Service "AzureCommunicationServices")Granit.Notifications.Email, Granit.Notifications.Sms
Granit.Notifications.AwsSnsAWS SNS provider — SMS + Platform Application push, each capability activated by its config section (Keyed Service "AwsSns")Granit.Notifications.Sms, Granit.Notifications.MobilePush
Granit.Notifications.BrevoUnified Brevo provider (Email + SMS + WhatsApp)Granit.Notifications.Email, Granit.Notifications.Sms, Granit.Notifications.WhatsApp
Granit.Notifications.TwilioTwilio SMS + WhatsApp provider (Keyed Service "Twilio")Granit.Notifications.Sms, Granit.Notifications.WhatsApp
Granit.Notifications.GoogleFcmFirebase Cloud Messaging (FCM HTTP v1 API, OAuth2 bearer via service account)Granit.Notifications.MobilePush
Granit.Notifications.AzureNotificationHubsAzure Notification Hubs push provider (Keyed Service "AzureNotificationHubs")Granit.Notifications.MobilePush
Granit.Notifications.SignalRReal-time SignalR channel + Redis backplaneGranit.Notifications
Granit.Notifications.WebPushW3C Web Push (VAPID, RFC 8030/8291/8292)Granit.Notifications
Granit.Notifications.WebPush.PrivacyGDPR export/deletion satellite for Web Push subscriptions (masked)Granit.Notifications.WebPush, Granit.Privacy.BlobStorage
Granit.Notifications.SseServer-Sent Events channel (.NET 10 native SSE)Granit.Notifications
Granit.Notifications.Sse.StackExchangeRedisRedis pub/sub backplane for multi-replica SSE delivery (shared IConnectionMultiplexer)Granit.Notifications.Sse
Granit.Notifications.ZulipZulip Bot API chat integrationGranit.Notifications
graph TD
    N[Granit.Notifications] --> G[Granit.Guids]
    N --> T[Granit.Timing]
    N --> Q[Granit.QueryEngine]

    NEF[Granit.Notifications.EntityFrameworkCore] --> N
    NEF --> MP[Granit.Notifications.MobilePush]
    NEF --> P[Granit.Persistence]

    NE[Granit.Notifications.Endpoints] --> N
    NE --> MP
    NE --> V[Granit.Validation]
    NE --> AD[Granit.Http.ApiDocumentation]

    NW[Granit.Notifications.Wolverine] --> N
    NW --> W[Granit.Wolverine]

    EM[Granit.Notifications.Email] --> N
    SMTP[Granit.Notifications.Smtp] --> EM
    SES[Granit.Notifications.AwsSes] --> EM
    SCW[Granit.Notifications.Scaleway] --> EM
    SG[Granit.Notifications.SendGrid] --> EM
    ACS[Granit.Notifications.AzureCommunicationServices] --> EM
    ACS --> SMS[Granit.Notifications.Sms]
    BR[Granit.Notifications.Brevo] --> EM
    BR --> SMS
    BR --> WA[Granit.Notifications.WhatsApp]

    SMS --> N
    SNS[Granit.Notifications.AwsSns] --> SMS
    SNS --> MP
    TW[Granit.Notifications.Twilio] --> SMS
    TW --> WA
    WA --> N
    MP --> N
    FCM[Granit.Notifications.GoogleFcm] --> MP
    ANH[Granit.Notifications.AzureNotificationHubs] --> MP
    SR[Granit.Notifications.SignalR] --> N
    WP[Granit.Notifications.WebPush] --> N
    SSE[Granit.Notifications.Sse] --> N
    SSER[Granit.Notifications.Sse.StackExchangeRedis] --> SSE
    ZU[Granit.Notifications.Zulip] --> N

    PRV[Granit.Notifications.Privacy] --> N
    MPPRV[Granit.Notifications.MobilePush.Privacy] --> MP
    WPPRV[Granit.Notifications.WebPush.Privacy] --> WP
[DependsOn(typeof(GranitNotificationsWolverineModule))]
[DependsOn(typeof(GranitNotificationsEntityFrameworkCoreModule))]
[DependsOn(typeof(GranitNotificationsEndpointsModule))]
public class AppModule : GranitModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// EF Core persistence (replaces in-memory defaults)
context.Builder.AddGranitNotificationsEntityFrameworkCore(
opts => opts.UseNpgsql(context.Configuration
.GetConnectionString("Notifications")));
// Email channel via SMTP
context.Services.AddGranitNotificationsEmail(opts => opts.Provider = "Smtp");
context.Services.AddGranitNotificationsSmtp();
// SignalR real-time channel with Redis backplane
context.Services.AddGranitNotificationsSignalR(
context.Configuration.GetConnectionString("Redis")!);
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
context.App.MapGranitNotifications();
context.App.MapHub<NotificationHub>("/hubs/notifications");
}
}

Modules that emit user-facing events (export ready, payment succeeded, quota exceeded…) ship a sibling Granit.{Module}.Notifications package wiring the event to the fan-out engine and providing the email templates. The notifications package conventions page documents the canonical file layout, the Wolverine handler shape, the <title>-tag subject extraction, the JSON-array *Display companion gotcha, the manifest pinning test, and the embedded-vs-DB template override mechanics.