Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

spring-notify

Channel-agnostic notification delivery for Spring Boot. Send SMS, push, email, and chat messages through one small API — your code talks to a channel, never to a provider. Swap Twilio for another SMS gateway, or FCM for APNs, by changing a dependency, not your code.

notifier.notify(SmsRequest.builder()
        .to("+421900123456")
        .from("+421900999888")
        .message("Your order has shipped")
        .build());

Latest release: 1.0.0 (on Maven Central) · Java 25 · Spring Boot 4.1 · no runtime dependencies beyond Spring and the provider SDK you choose.

📖 Full documentation lives in docs/. This page is the overview.


Why

Most apps end up with provider SDKs (TwilioRestClient, FirebaseMessaging, a JavaMailSender, a Slack client) threaded directly through business code. Switching providers, adding a channel, or testing delivery then means touching every call site.

spring-notify puts a thin, provider-neutral layer in front:

  • One entry point — inject Notifier, call notify(request).
  • Typed, immutable requestsSmsRequest, PushRequest, EmailRequest, ChatRequest (fluent builders; jspecify-annotated, validated at build time).
  • Providers are plug-ins — each is a separate starter that contributes one *Sender bean. Auto-configuration wires it in when it's configured.
  • Routing by type — the request's concrete type selects the channel; no if/switch in your code.

Quick start

1. Add a provider starter — it pulls in the channel and pipeline transitively:

<dependency>
    <groupId>sk.solodev</groupId>
    <artifactId>notify-spring-boot-starter-sms-twilio</artifactId>
    <version>1.0.0</version>
</dependency>

2. Configure it (application.yml) — keys autocomplete in your IDE:

spring:
  notify:
    sms:
      twilio:
        account-sid: ${TWILIO_ACCOUNT_SID}
        auth-token: ${TWILIO_AUTH_TOKEN}

3. Inject Notifier and send:

String messageId = notifier.notify(SmsRequest.builder()
        .to(order.phone())
        .from("+421900999888")
        .message("Your order has shipped")
        .build());

notify(...) returns the provider message id, or throws NotificationDeliveryException (carrying the failed request) on failure. Use notifyAsync(...) to send off the calling thread.

Getting started covers the BOM, async, and the full walkthrough.


Channels & providers

Channel Request Provider starters
SMS SmsRequest …-sms-twilio, …-sms-vonage
Push PushRequest …-push-fcm, …-push-apns
Email EmailRequest …-email-smtp, …-email-sendgrid
Chat ChatRequest …-chat-slack

Providers are interchangeable. Each channel takes the same request whichever backend you install — you pick it with a dependency, not a code change. Your app code never mentions Twilio, Vonage, FCM, APNs, or SendGrid. Not using a bundled provider? Depend on the channel module and supply your own *Sender bean.

Providers has configuration for every backend · Channels documents the request fields.


What else it does

  • Asynchronous sendingnotifyAsync runs the pipeline off-thread on Boot's task executor (virtual-thread and context-propagation aware). → Concepts
  • Observability — a Micrometer timer, span, and logs per send when an ObservationRegistry is present; delivery-scoped by design. → Observability & events
  • Lifecycle eventsNotificationSent / NotificationFailed published per send for audit, dead-lettering, or retry. → Observability & events
  • Interceptors — wrap every send (or one channel) for logging, rate limiting, retry, kill switches. → Interceptors
  • Transactional outbox — persist a send in your business transaction; a relay delivers it durably afterwards, safe across instances. → Transactional outbox
  • Test doubleRecordingNotifier asserts sends without a real provider. → Testing

How it fits together

your code → Notifier.notify(request)
              → NotificationInterceptor chain      (ordered, optional)
              → AdapterResolver                    (picks the adapter by request type)
              → ChannelAdapter.deliver(request)    (wraps failures, returns message id)
                  → NotificationSender.send(request)   (the provider call: Twilio/FCM/SMTP/Slack)
  • notify-core — the pipeline and contracts. No provider dependencies.
  • notify-spring-boot-<channel> — a channel: its request type, *Sender SPI, and a generic adapter.
  • notify-spring-boot-starter-<channel>-<provider> — one provider implementation you install.

You depend on a provider starter; everything below it comes transitively.

Concepts explains routing, the error model, and immutability.


Requirements

  • Java 25
  • Spring Boot 4.1+

What's next

  • More providers per channel — SMS (AWS SNS), email (SES), chat (Discord).

Contributions and provider requests welcome.

License

Apache License 2.0 — see LICENSE.

About

Channel-agnostic notification delivery for Spring Boot — send SMS, push, email, and chat through one API.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages