Skip to content

Channels

GrydNotifications supports three notification channels out of the box: Email, Push, and In-App. Each channel has its own provider abstraction, allowing you to swap implementations without changing application code.

Channel Architecture

                    SendNotificationCommand

                    ┌───────┴───────┐
                    │  Channel      │
                    │  Resolver     │
                    └───┬───┬───┬───┘
                        │   │   │
              ┌─────────┘   │   └─────────┐
              ▼             ▼             ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │  Email   │ │   Push   │ │  In-App  │
        │ Provider │ │ Provider │ │  Sender  │
        └────┬─────┘ └────┬─────┘ └────┬─────┘
             │             │             │
        ┌────┴────┐   ┌───┴────┐   ┌────┴────┐
        │ MailKit │   │  FCM   │   │ SignalR  │
        │ SendGrid│   │        │   │ + DB     │
        └─────────┘   └────────┘   └──────────┘

Email Channel

The email channel supports SMTP via MailKit (default) and SendGrid as an alternative provider.

MailKit (SMTP) — Default

MailKit is the default email provider, recommended by Microsoft over System.Net.Mail. It supports OAuth2, connection pooling, DKIM, and S/MIME.

csharp
options.Email.SmtpHost = "smtp.myapp.com";
options.Email.SmtpPort = 587;
options.Email.SmtpUseSsl = true;
options.Email.SmtpUsername = "user";
options.Email.SmtpPassword = "password";
options.Email.DefaultFrom = "noreply@myapp.com";
options.Email.DefaultFromName = "My App";

Sending Emails

csharp
// Via unified pipeline
await _mediator.Send(new SendNotificationCommand
{
    Channel = NotificationChannel.Email,
    Recipients = [
        new RecipientDto("john@example.com", "John Doe"),
        new RecipientDto("jane@example.com", "Jane Doe")
    ],
    Subject = "Weekly Report",
    HtmlBody = "<h1>Your weekly report is ready</h1>",
    TextBody = "Your weekly report is ready"
}, ct);

// Via direct email shortcut
await _mediator.Send(new SendEmailCommand
{
    To = ["john@example.com"],
    Cc = ["manager@example.com"],
    Bcc = ["audit@myapp.com"],
    Subject = "Quarterly Summary",
    HtmlBody = "<h1>Q4 2025 Summary</h1>",
    FromAddress = "reports@myapp.com",
    FromName = "Reports System"
}, ct);

Email with Attachments

csharp
await _mediator.Send(new SendEmailCommand
{
    To = ["user@example.com"],
    Subject = "Invoice Attached",
    HtmlBody = "<p>Please find your invoice attached.</p>",
    Attachments = [
        new AttachmentDto
        {
            FileName = "invoice.pdf",
            ContentType = "application/pdf",
            Content = pdfBytes
        }
    ]
}, ct);

Email Limits

LimitDefaultConfigurable
Max attachment size10 MBMaxAttachmentSizeMb
Max attachments/email5MaxAttachmentsPerEmail
Max recipients (To+Cc+Bcc)50MaxRecipientsPerEmail
Bulk batch size100BulkBatchSize

SendGrid Provider

For high-volume sending, use SendGrid's HTTP API:

csharp
// SendGrid is available as an additional provider
// Configure SMTP credentials for SendGrid
options.Email.SmtpHost = "smtp.sendgrid.net";
options.Email.SmtpUsername = "apikey";
options.Email.SmtpPassword = "SG.your_api_key_here";

Push Channel (FCM)

The push channel sends notifications via Firebase Cloud Messaging to mobile devices and web browsers.

Setup

  1. Create a Firebase project at console.firebase.google.com
  2. Download the service account JSON
  3. Set the environment variable:
bash
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/firebase-adminsdk.json"
  1. Enable push in options:
csharp
options.Push.Enabled = true;
options.Push.DefaultTimeToLive = TimeSpan.FromHours(24);
options.Push.AutoRemoveInvalidTokens = true;

Sending Push Notifications

csharp
// Direct push to device tokens
await _mediator.Send(new SendPushNotificationCommand
{
    Title = "New Message",
    Body = "You have a new message from John",
    DeviceTokens = ["device_token_1", "device_token_2"],
    Data = new Dictionary<string, string>
    {
        ["messageId"] = "abc123",
        ["type"] = "new_message"
    }
}, ct);

// Via unified pipeline
await _mediator.Send(new SendNotificationCommand
{
    Channel = NotificationChannel.Push,
    Recipients = [new RecipientDto { Address = "device_token_abc" }],
    Subject = "New Message",
    TextBody = "You have a new message from John"
}, ct);

Device Token Management

GrydNotifications tracks device tokens per user with automatic lifecycle management:

FeatureDescription
RegistrationStore tokens when users sign in on devices
DeactivationAuto-deactivate tokens reported invalid by FCM
Stale cleanupRemove tokens unused for StaleTokenThreshold (default 90 days)
Multicast limitAuto-splits sends into batches of MaxDeviceTokensPerMulticast (500)

FCM Payload Customization

csharp
await _mediator.Send(new SendPushNotificationCommand
{
    Title = "Flash Sale!",
    Body = "50% off all items — ends in 2 hours",
    DeviceTokens = tokens,
    ImageUrl = "https://cdn.myapp.com/sale-banner.jpg",
    Data = new Dictionary<string, string>
    {
        ["screen"] = "promotions",
        ["promo_id"] = "FLASH50"
    }
}, ct);

In-App Channel

The in-app channel creates notifications for the user's bell/drawer in your application. Notifications are persisted in the database and delivered in real-time via SignalR.

For a detailed guide on the In-App channel, see In-App & SignalR.

Quick Overview

csharp
// Send an in-app notification
await _mediator.Send(new SendInAppNotificationCommand
{
    UserId = userId,
    Title = "Task Assigned",
    Body = "You've been assigned to task #123",
    Icon = "📋",
    Category = "tasks",
    ActionUrl = "/tasks/123",
    Priority = NotificationPriority.High
}, ct);

Features

FeatureDescription
Read/Unread trackingMark individual or all as read
CategoriesFilter by category (alerts, tasks, comments, etc.)
ExpirationAuto-expire with ExpiresAfter
Collapse keysGroup related notifications
Real-time (SignalR)Instant delivery via WebSocket
Badge countUnread count endpoint for UI badge

Multi-Channel Sending

Send the same notification to multiple channels:

csharp
// Email + In-App
var notification = new SendNotificationCommand
{
    Channel = NotificationChannel.Email,
    Recipients = [new RecipientDto("user@example.com")],
    TemplateSlug = "order-confirmation",
    TemplateData = templateData
};

await _mediator.Send(notification, ct);

// Also create an in-app notification
await _mediator.Send(new SendInAppNotificationCommand
{
    UserId = userId,
    Title = "Order Confirmed",
    Body = $"Your order #{orderId} is confirmed",
    Category = "orders",
    ActionUrl = $"/orders/{orderId}"
}, ct);

Provider Abstraction

Each channel is defined by an abstraction in GrydNotifications.Core:

AbstractionDescription
IEmailSenderEmail delivery (MailKit, SendGrid)
IPushNotificationSenderPush delivery (FCM)
IInAppNotificationSenderIn-app create + SignalR broadcast
INotificationTemplateRendererTemplate compilation + rendering (Scriban)
INotificationQueueAsync processing queue

To swap a provider, register your implementation:

csharp
// Replace the default email sender
services.AddSingleton<IEmailSender, MyCustomEmailSender>();

Released under the MIT License.