APiGen Notifications
Multi-channel notification delivery system with template management, delivery tracking, user preferences, real-time WebSocket delivery, and robust retry logic.
🎯 Features
- 5 Notification Channels: Email, SMS, Push (Mobile), In-App, Webhook
- Multi-Provider Support: SendGrid, Mailgun, AWS SES (Email) | Twilio, AWS SNS (SMS) | FCM, APNs (Push)
- 4 Template Engines: Thymeleaf, Mustache, FreeMarker, Simple variable substitution
- User Preferences: Per-channel, category-based, quiet hours with timezone support
- Delivery Tracking: Full lifecycle tracking with engagement metrics (opens, clicks)
- Bulk Sending: Parallel batch processing with configurable delay
- Real-Time WebSocket: Push notifications to connected clients
- Retry Logic: Exponential backoff with configurable strategies
- Rate Limiting: Per-channel and global limits
- Async Operations: Non-blocking with CompletableFuture
- Multi-Locale: Template support for multiple languages
🚀 Quick Start
1. Configuration
yaml
apigen:
notifications:
enabled: true
default-from-email: noreply@example.com
default-from-name: "My App"
# Email Provider
email:
provider: sendgrid # Options: sendgrid, ses, mailgun
sendgrid:
api-key: ${SENDGRID_API_KEY}
# SMS Provider
sms:
provider: twilio # Options: twilio, sns
twilio:
account-sid: ${TWILIO_ACCOUNT_SID}
auth-token: ${TWILIO_AUTH_TOKEN}
from-number: "+1234567890"
# Push Notifications
push:
fcm:
enabled: true
credentials-path: /path/to/firebase-credentials.json
apns:
enabled: false
# Template Engine
template:
engine: thymeleaf # Options: thymeleaf, mustache, freemarker, simple
path: classpath:/templates/notifications/
cache-enabled: true
cache-ttl: 5m
# Tracking
tracking:
enabled: true
track-opens: true
track-clicks: true2. Send Your First Notification
java
@Service
public class WelcomeService {
private final NotificationService notificationService;
public void sendWelcomeEmail(User user) {
NotificationRequest request = NotificationRequest.builder()
.channel(NotificationChannel.EMAIL)
.recipient(user.getEmail())
.subject("Welcome to Our Platform!")
.templateName("welcome")
.templateData(Map.of(
"userName", user.getName(),
"verificationLink", generateVerificationLink(user)
))
.priority(NotificationPriority.HIGH)
.build();
// Async send
notificationService.sendAsync(request)
.thenAccept(result -> {
if (result.isSuccess()) {
log.info("Welcome email sent: {}", result.getNotificationId());
} else {
log.error("Failed to send: {}", result.getError());
}
});
}
}📢 Notification Channels
Email Providers
| Provider | Features | Use Case |
|---|---|---|
| SendGrid | High deliverability, analytics, templates | Marketing + Transactional |
| Mailgun | Developer-friendly, routing, webhooks | Transactional |
| AWS SES | Low cost, AWS integration, bounce handling | High volume |
SMS Providers
| Provider | Features | Coverage |
|---|---|---|
| Twilio | Global reach, programmable messaging, delivery reports | Worldwide |
| AWS SNS | AWS integration, cost-effective, pub/sub | Worldwide |
Push Providers
| Provider | Platform | Features |
|---|---|---|
| FCM (Firebase Cloud Messaging) | Android + iOS | Topics, device groups, analytics |
| APNs (Apple Push Notification Service) | iOS only | Silent pushes, rich media |
📊 Delivery Tracking
Track Engagement
java
// Track email opens
trackingService.trackEvent(notificationId, DeliveryEvent.OPENED, Instant.now());
// Track link clicks
trackingService.trackEvent(notificationId, DeliveryEvent.CLICKED,
Instant.now(), Map.of("linkUrl", "https://..."));
// Track unsubscribes
trackingService.trackEvent(notificationId, DeliveryEvent.UNSUBSCRIBED, Instant.now());⚡ Real-Time WebSocket Delivery
Client Connection
javascript
// JavaScript client
const ws = new WebSocket('ws://localhost:8080/ws/notifications?userId=user_123');
ws.onopen = () => {
console.log('Connected to notification stream');
// Send ping to keep alive
setInterval(() => {
ws.send(JSON.stringify({ type: 'PING' }));
}, 30000);
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case 'NOTIFICATION':
showNotification(message.payload);
break;
case 'UNREAD_COUNT':
updateBadge(message.payload.count);
break;
case 'PONG':
console.log('Server alive');
break;
}
};