DEV Community

Cover image for I Got Tired of Wiring Up Notifications From Scratch — So I Built a Library
RecurPixel
RecurPixel

Posted on

I Got Tired of Wiring Up Notifications From Scratch — So I Built a Library

Every time I start a new project, there's always that moment.

The feature list is done, the architecture is clean, the database schema makes sense — and then someone says "we need to send notifications."

And just like that, the clean project gets messy.


A dark-themed promotional banner for RecurPixel.Notify, an open-source ASP.NET Core notification library. The left side displays the library name in large white and green text with the tagline

The Problem I Kept Running Into

On one of my recent projects, I had to integrate:

  • SendGrid for transactional email
  • Twilio for SMS OTPs
  • FCM for Android push notifications
  • Slack for internal alerts
  • WhatsApp for order updates

Five different SDKs. Five different configuration patterns. Five different error handling styles. Five sets of retry logic written from scratch because each provider fails differently.

And the worst part? I'd solved this before. On a different project. With slightly different providers. And I'd have to solve it again on the next one.

There was no clean .NET library that handled all of this with a consistent interface. The SaaS options (Novu, Courier, Knock) meant sending user data to an external platform and paying per notification. FluentEmail only covers email. Everything else was either abandoned, Node.js only, or built for a single provider.

So I built one.

A dark-themed promotional banner for RecurPixel.Notify, an open-source ASP.NET Core notification library. The left side displays the library name in large white and green text with the tagline


Introducing RecurPixel.Notify

A modular, DI-native notification library for ASP.NET Core.

No external platform. No account sign-up. No per-notification billing. Drop the NuGet package in, bring your own API keys, own your data completely.

dotnet add package RecurPixel.Notify.Sdk
Enter fullscreen mode Exit fullscreen mode

One interface for everything:

// Send an email
await notify.Email.SendAsync(new NotificationPayload
{
    To      = user.Email,
    Subject = "Order Confirmed",
    Body    = emailHtml
});

// Send an SMS
await notify.Sms.SendAsync(new NotificationPayload
{
    To   = user.Phone,
    Body = $"Your OTP is {otp}. Valid for 5 minutes."
});

// Trigger a multi-channel event — email + SMS + push, in parallel
await notify.TriggerAsync("order.placed", new NotifyContext
{
    User     = notifyUser,
    Channels = new()
    {
        ["email"] = new() { Subject = "Order Confirmed", Body = emailHtml },
        ["sms"]   = new() { Body = $"Order #{order.Id} confirmed." },
        ["push"]  = new() { Subject = "Order Confirmed", Body = "Tap to view." }
    }
});
Enter fullscreen mode Exit fullscreen mode

Swap SendGrid for Postmark? One config line. Switch from Twilio to Vonage? Same. Your application code never changes.


What's Supported Right Now (Beta)

The library just hit v0.1.0-beta.1 with 20+ adapters across 5 channel categories:

Channel Providers
📧 Email SendGrid, SMTP
💬 SMS Twilio
🔔 Push Firebase (FCM), Apple (APNs)
📱 WhatsApp Twilio, Meta Cloud API
🤝 Team Chat Slack, Discord, Microsoft Teams

And it's not just single sends. Providers with native batch APIs use them automatically:

// FCM multicast — 500 device tokens per API call under the hood
var result = await notify.Push.SendBulkAsync(devicePayloads);

Console.WriteLine($"{result.SuccessCount}/{result.Total} delivered");
foreach (var failure in result.Failures)
    logger.LogWarning("Failed: {Recipient} — {Error}", failure.Recipient, failure.Error);
Enter fullscreen mode Exit fullscreen mode

Features I'm Proud Of

Retry with exponential backoff — configure globally or per event. Providers fail. The library handles it.

Cross-channel fallback chains — WhatsApp fails, try SMS, fail again, try email. All automatic.

Conditions — don't send SMS to unverified numbers, don't send push to users who opted out. Evaluated at runtime from your own data.

Parallel dispatch — multi-channel events fire all channels simultaneously via Task.WhenAll.

Delivery hooks — a single callback gives you every result. You write to your own log table in your own schema.

Named provider routing — route transactional email to Postmark, marketing email to AWS SES, from the same notify.Email.SendAsync call.

// Goes to Postmark
new NotificationPayload { ..., Metadata = new() { ["provider"] = "transactional" } }

// Goes to AWS SES
new NotificationPayload { ..., Metadata = new() { ["provider"] = "marketing" } }
Enter fullscreen mode Exit fullscreen mode

Three Ways to Use It

The library is modular by design. Install only what you need.

Tier 1 — Single channel, no orchestrator:

dotnet add package RecurPixel.Notify.Email.SendGrid
Enter fullscreen mode Exit fullscreen mode

Register and inject a single INotificationChannel. Perfect for OTP flows or single-channel apps.

Tier 2 — Core + Orchestrator + your providers:

dotnet add package RecurPixel.Notify.Core
dotnet add package RecurPixel.Notify.Orchestrator
dotnet add package RecurPixel.Notify.Email.SendGrid
dotnet add package RecurPixel.Notify.Sms.Twilio
Enter fullscreen mode Exit fullscreen mode

Full event system, conditions, retry, fallback — only the providers you configure.

Tier 3 — Full SDK:

dotnet add package RecurPixel.Notify.Sdk
Enter fullscreen mode Exit fullscreen mode

Everything pre-packaged. Configure what you use in appsettings.json. Everything else stays dormant.


What I'd Love to See You Build With It

This is the part that actually excites me.

A SaaS marketing platform — RecurPixel.Notify handles all the delivery mechanics. You focus on audience segmentation, templates, and scheduling. The multi-channel bulk send and delivery hooks give you everything you need to build a proper notification pipeline.

An open-source desktop notification app — imagine a cross-platform Electron/Avalonia app that lets non-technical users configure and send notifications across all these providers without writing a line of code. The library is already doing the hard part.

A self-hosted notification service — wrap it in a minimal API, add a queue, expose a REST endpoint. You now have your own private alternative to Courier or Novu with no external data dependency.

Internal developer tools — Slack + Teams + Discord alerts for deployments, errors, and monitoring, all wired through a single service with retry and fallback.

If you build something with it, I genuinely want to hear about it.


What's Coming Next

This is 0.1.0-beta.1 — the foundation is solid, the adapter pattern is proven, and the core features are all there. Here's what I'm building toward:

v0.2.0 — Telegram, Facebook Messenger, LINE, Viber, and the in-app inbox channel.

v0.3.0 — Remaining providers: Mailgun, Resend, Postmark, AWS SES, Vonage, Sinch, OneSignal, Expo Push. That takes the total to 27+ providers.

v1.0.0 — Stable API, full integration test coverage, community-approved adapters. This is the production-ready milestone.

Beyond that — performance profiling on large bulk sends, possible source generator for compile-time event validation, and who knows — maybe that open-source desktop app. Happy to explore it with anyone interested.


Try It, Break It, Tell Me

dotnet add package RecurPixel.Notify.Sdk --version 0.1.0-beta.1 --prerelease
Enter fullscreen mode Exit fullscreen mode

This is a beta. Some adapters are thoroughly tested. Some are implemented but not yet integration-tested against real provider sandboxes. The architecture is solid — individual adapter bugs are absolutely possible and that's what beta is for.

If you hit an issue, open a GitHub issue. If something works beautifully, even better — let me know.

GitHub: github.com/recurpixel/notify

NuGet: nuget.org/packages/RecurPixel.Notify.Sdk

Docs: recurpixel.io/Notify/


Built because I got tired of writing the same notification wiring code on every project. Hope it saves you some of that time too.


Tags: #dotnet #aspnetcore #csharp #nuget #notifications #openSource #programming

Top comments (0)