[0.3.0] — May 2026
New Packages
RecurPixel.Notify.Dashboard— delivery observability middleware, embedded UI, REST API,INotificationLogStoreRecurPixel.Notify.Dashboard.EfCore— EF Core implementation,NotifyDashboardDbContext,AddNotifyDashboard()integrationRecurPixel.Notify.Sms.Msg91— MSG91 SMS adapterRecurPixel.Notify.WhatsApp.Msg91— MSG91 WhatsApp Business adapter
Both MSG91 packages are included in RecurPixel.Notify.Sdk alongside both Dashboard packages.
New Features
NotifyResult improvements
Three new fields on every NotifyResult, with zero breaking changes:
public string? EventName { get; set; } // which event triggered this send
public string? BulkBatchId { get; set; } // groups all results from one BulkTriggerAsync call
public Dictionary<string, object>? Metadata { get; set; } // passthrough from NotifyContextBulkBatchId is a Guid generated once per BulkTriggerAsync call and stamped on every result in the batch — this is what makes the dashboard's "view all in this batch" drill-down possible. EventName and Metadata give OnDelivery handlers full context without any changes to existing hook code.
Dashboard
Drop-in delivery log dashboard. Pattern is identical to Hangfire — one middleware call, zero Razor/Blazor dependencies.
// Program.cs
builder.Services.AddNotifyDashboard(options =>
{
options.RoutePrefix = "notify-dashboard";
options.RequireRole = "Admin";
});
// Option A — standalone context (own connection string, own migration)
builder.Services.AddNotifyDashboardEfCore(db =>
db.UseSqlite(connectionString));
// Option B — plug into your existing DbContext (one DB, one migration)
// Your DbContext must call builder.AddNotifyDashboard() in OnModelCreating.
builder.Services.AddDbContext<AppDbContext>(db => db.UseSqlite(connectionString));
builder.Services.AddNotifyDashboardEfCore<AppDbContext>();
app.UseNotifyDashboard();What it shows: summary row (total today, success rate, failure count, active channels), filterable log table with channel/provider/status badges, bulk row expansion (all recipients in a batch grouped inline), failed row expansion (full error text), filters by channel, status, date range, and recipient.
Bring-your-own-store: implement INotificationLogStore and skip the EfCore package entirely.
MSG91 adapters
"Sms": { "Provider": "msg91", "Msg91": { "AuthKey": "...", "SenderId": "NOTIFY" } }
"WhatsApp": { "Provider": "msg91", "Msg91": { "AuthKey": "...", "IntegratedNumber": "91XXXXXXXXXX" } }No native bulk API on either — base class loop handles bulk automatically.
IAdapterRegistrar refactor — 10 bug fixes
Auto-registration is now driven by one IAdapterRegistrar per adapter package rather than two monolithic switch/case tables in the Orchestrator. Fixes shipped in this refactor:
| Bug | Fix |
|---|---|
FCM gated on ProjectId instead of ServiceAccountJson |
FCM registrar gates on ServiceAccountJson |
FCM crash — IFcmMessagingClient not registered |
FCM registrar registers IFcmMessagingClient |
AwsSns crash — IAmazonSimpleNotificationService not registered |
AwsSns registrar registers it |
AwsSes crash — IAmazonSimpleEmailServiceV2 not registered |
AwsSes registrar registers it |
AzureCommSms crash — IAzureCommSmsClient not registered |
AzureCommSms registrar registers it |
AzureCommEmail crash — IAzureCommEmailClient not registered |
AzureCommEmail registrar registers it |
| Twilio SMS and WhatsApp credentials overwrite each other | Named options isolation: "sms:twilio" / "whatsapp:twilio" |
19 HTTP adapters used unnamed HttpClient — no timeout, no DNS rotation |
All HTTP registrars register named clients with 30s timeout |
MetaCloud used key "whatsapp:metacloud" in channel, "whatsapp:metacloudwhatsapp" in registrar |
Both normalised to "whatsapp:metacloud" |
All Add{X}Channel() explicit methods bypassed the registrar |
All explicit methods delegate to their registrar |
Bug Fixes
NotifyOptionsValidatornow accepts"msg91"as a valid SMS provider and WhatsApp providerNotifyOptionsValidatornow accepts"azurecommsms"as a valid SMS providerNotifyOptionsValidatornow accepts"azurecommemail"as a valid Email providerSmsOptions.ProviderandWhatsAppOptions.Providerdoc comments updated to list all accepted values- InApp channel registration order —
InAppRegistrarnow usesTryAddSingletonfor the default empty options so that callingAddInAppChannel(opts => opts.UseHandler(...))beforeAddRecurPixelNotify()correctly preserves the user-configured handler
No Breaking Changes
All existing code compiles without modification. New NotifyResult fields default to null. Existing OnDelivery handlers work unchanged. Add{X}Channel() explicit methods still exist with the same signatures.
Adapter Status in v0.3.0
| Package | Provider | Channel | Unit Tested | Integration Tested |
|---|---|---|---|---|
Email.SendGrid |
Twilio SendGrid | ✅ | ✅ | |
Email.Smtp |
Any SMTP server | ✅ | ✅ | |
Email.Mailgun |
Mailgun | ✅ | 🔲 | |
Email.Resend |
Resend | ✅ | 🔲 | |
Email.Postmark |
Postmark | ✅ | 🔲 | |
Email.AwsSes |
AWS SES | ✅ | 🔲 | |
Email.AzureCommEmail |
Azure Communication Services | ✅ | 🔲 | |
Sms.Twilio |
Twilio | SMS | ✅ | ✅ |
Sms.Vonage |
Vonage (Nexmo) | SMS | ✅ | 🔲 |
Sms.Plivo |
Plivo | SMS | ✅ | 🔲 |
Sms.Sinch |
Sinch | SMS | ✅ | 🔲 |
Sms.MessageBird |
MessageBird | SMS | ✅ | 🔲 |
Sms.AwsSns |
AWS SNS | SMS | ✅ | 🔲 |
Sms.AzureCommSms |
Azure Communication Services | SMS | ✅ | 🔲 |
Sms.Msg91 |
MSG91 | SMS | ✅ | ✅ |
Push.Fcm |
Firebase Cloud Messaging | Push | ✅ | 🔲 |
Push.Apns |
Apple Push Notification Service | Push | ✅ | 🔲 |
Push.OneSignal |
OneSignal | Push | ✅ | 🔲 |
Push.Expo |
Expo Push | Push | ✅ | 🔲 |
WhatsApp.Twilio |
Twilio WhatsApp | ✅ | ✅ | |
WhatsApp.MetaCloud |
Meta Cloud API | ✅ | 🔲 | |
WhatsApp.Vonage |
Vonage WhatsApp | ✅ | 🔲 | |
WhatsApp.Msg91 |
MSG91 WhatsApp | ✅ | ✅ | |
Slack |
Slack Webhooks / Bot API | Team Chat | ✅ | ✅ |
Discord |
Discord Webhooks | Team Chat | ✅ | ✅ |
Teams |
Microsoft Teams Webhooks | Team Chat | ✅ | 🔲 |
Mattermost |
Mattermost Webhooks | Team Chat | ✅ | 🔲 |
RocketChat |
Rocket.Chat Webhooks | Team Chat | ✅ | 🔲 |
Facebook |
Meta Messenger API | Social | ✅ | 🔲 |
Telegram |
Telegram Bot API | Social | ✅ | ✅ |
Line |
LINE Messaging API | Social | ✅ | 🔲 |
Viber |
Viber Business Messages | Social | ✅ | 🔲 |
InApp |
Hook-based (user-defined storage) | In-App | ✅ | ✅ |
Tests: 442 passing