Skip to main content

Notification Best Practices

Implement these best practices to maximize the effectiveness of notifications while maintaining positive user experiences.

Channel Selection

Choose the appropriate channel based on message urgency and user preferences:

ChannelBest ForNot Recommended For
SMSTime-sensitive alerts, 2FA codesMarketing content, non-critical updates
EmailDetailed information, receipts, reportsUrgent alerts requiring immediate action
WhatsAppInteractive conversations, rich mediaUnsolicited marketing messages
In-AppContext-specific updates, system statusCritical security alerts when app is closed

Recommendation: Implement a preference center that allows users to select their preferred channels for different notification types.

Message Content

SMS

  • Keep messages under 160 characters to avoid message splitting
  • Include a clear call-to-action if applicable
  • Identify your organization at the beginning of the message
  • Use URL shorteners for any links
// Good example
string goodSmsMessage = "Lightstone: Your verification code is 123456. Valid for 10 minutes. Do not share this code.";

// Poor example - too long, unclear sender
string poorSmsMessage = "Your one-time password for verifying your account on our platform is 123456. This code will expire in 10 minutes. Please enter it on the verification screen to complete your registration process. Thank you for using our service.";

Email

  • Use descriptive subject lines (4-7 words)
  • Design for mobile-first viewing
  • Include plain text alternatives to HTML
  • Keep email width between 600-800 pixels

WhatsApp

  • Follow WhatsApp Business Policy guidelines
  • Obtain explicit opt-in before messaging
  • Use templates for consistency
  • Keep messages concise and conversational

Timing and Frequency

  • Respect user time zones when scheduling notifications
  • Implement rate limiting to prevent notification fatigue
  • Group related notifications to reduce interruptions
  • Allow users to snooze or temporarily disable notifications
// Example rate limiting implementation
public class NotificationRateLimiter
{
private readonly Dictionary<string, int> _maxNotificationsPerHour = new Dictionary<string, int>
{
{ "sms", 2 },
{ "email", 5 },
{ "whatsapp", 3 },
{ "inApp", 10 }
};

public bool ShouldSendNotification(string userId, string channelType)
{
// Check if user has received max notifications for this channel
var recentNotifications = GetRecentNotifications(userId, channelType);

return recentNotifications.Count < _maxNotificationsPerHour[channelType];
}

private List<Notification> GetRecentNotifications(string userId, string channelType)
{
// Implementation to retrieve recent notifications from database
// This would query notifications from the last hour
return new List<Notification>();
}
}

Error Handling

Implement robust error handling to ensure notification delivery:

  1. Retry Logic: Implement exponential backoff for failed notifications
public class NotificationSender
{
public async Task<NotificationResult> SendWithRetry(Notification notification, int maxRetries = 3)
{
for (int attempt = 0; attempt <= maxRetries; attempt++)
{
try
{
return await SendNotification(notification);
}
catch (Exception ex)
{
if (attempt == maxRetries)
throw;

// Wait 2^attempt seconds before retrying
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));

// Log retry attempt
_logger.LogWarning($"Retry attempt {attempt + 1} for notification {notification.Id}. Error: {ex.Message}");
}
}

// This line should not be reached, but required by compiler
throw new InvalidOperationException("Failed to send notification after retries");
}

private async Task<NotificationResult> SendNotification(Notification notification)
{
// Implementation of actual notification sending logic
return new NotificationResult();
}
}
  1. Fallback Channels: Configure alternative channels if primary channel fails
public class NotificationService
{
private readonly ISmsService _smsService;
private readonly IEmailService _emailService;
private readonly ILogger<NotificationService> _logger;

public NotificationService(ISmsService smsService, IEmailService emailService, ILogger<NotificationService> logger)
{
_smsService = smsService;
_emailService = emailService;
_logger = logger;
}

public async Task<DeliveryResult> SendWithFallback(NotificationRequest notification)
{
try
{
return await _smsService.SendNotification(notification);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "SMS delivery failed, attempting email fallback");
return await _emailService.SendNotification(notification);
}
}
}
  1. Monitor Delivery Rates: Track delivery success rates across channels
    • Log all notification attempts and outcomes
    • Set up alerts for abnormal failure rates
    • Review delivery metrics weekly to identify problem areas

Security Considerations

  • Never include sensitive information in notifications
  • Implement proper authentication for notification APIs
  • Rotate API keys regularly
  • Use TLS for all API communications
  • Validate all input data before sending notifications
public static class PhoneValidator
{
// Validate phone numbers before sending
public static bool ValidatePhoneNumber(string phoneNumber, string countryCode)
{
// Strip any non-numeric characters
string cleaned = Regex.Replace(phoneNumber, @"\D", "");

// Validate based on country code
var patterns = new Dictionary<string, string>
{
{ "ZA", @"^(0\d{9})$" },
{ "US", @"^\d{10}$" }
// Add other countries as needed
};

if (patterns.TryGetValue(countryCode, out string pattern))
{
return Regex.IsMatch(cleaned, pattern);
}

return false;
}
}

Testing Strategy

Test notifications thoroughly before production deployment:

  1. Sandbox Testing: Test in isolated environments with known test numbers/emails
  2. Template Validation: Verify template rendering across device types
  3. Load Testing: Ensure systems handle peak notification volumes
  4. End-to-end Testing: Test entire notification flow from trigger to delivery
  5. Compliance Testing: Verify notifications meet regulatory requirements

Create dedicated test accounts for each notification channel:

public static class TestAccounts
{
public static readonly TestEnvironment Accounts = new TestEnvironment
{
SmsTestAccount = new SmsAccount
{
Number = "0000000000",
CountryCode = "ZA"
},
EmailTestAccount = "test-notifications@yourdomain.com",
WhatsAppTestAccount = new WhatsAppAccount
{
Number = "0000000000",
CountryCode = "ZA"
}
};
}

public class TestEnvironment
{
public SmsAccount SmsTestAccount { get; set; }
public string EmailTestAccount { get; set; }
public WhatsAppAccount WhatsAppTestAccount { get; set; }
}

public class SmsAccount
{
public string Number { get; set; }
public string CountryCode { get; set; }
}

public class WhatsAppAccount
{
public string Number { get; set; }
public string CountryCode { get; set; }
}

Performance Optimization

Optimize notification processing for high-volume scenarios:

  1. Batch Processing: Group notifications when sending to multiple recipients
// Batch SMS example
POST /Sms/SendBatch
{
"body": "Your account has been updated",
"sendTo": [
{ "address": "0123456789", "countryCode": "ZA" },
{ "address": "0123456790", "countryCode": "ZA" },
{ "address": "0123456791", "countryCode": "ZA" }
]
}
  1. Asynchronous Processing: Queue notifications for background processing
public class NotificationQueue
{
private readonly IServiceScopeFactory _scopeFactory;

public NotificationQueue(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}

public async Task QueueNotificationAsync(Notification notification)
{
// Add to queue
await _notificationQueue.EnqueueAsync(notification);

// Process in background
_ = Task.Run(async () => await ProcessQueueAsync());
}

private async Task ProcessQueueAsync()
{
using var scope = _scopeFactory.CreateScope();
var sender = scope.ServiceProvider.GetRequiredService<INotificationSender>();

while (await _notificationQueue.TryDequeueAsync(out var notification))
{
try
{
await sender.SendAsync(notification);
}
catch (Exception ex)
{
// Log exception and potentially requeue with backoff
}
}
}
}
  1. Priority Queues: Implement priority-based sending for time-sensitive alerts
  2. Caching: Cache template data and user preferences to reduce database load

Analytics and Improvement

Track notification effectiveness to continuously improve your strategy:

  1. Delivery Rates: Monitor successful deliveries across channels
  2. Open/Click Rates: Track engagement with notification content
  3. Conversion Tracking: Measure actions taken after notification receipt
  4. A/B Testing: Test different message formats and timing to optimize engagement

Compliance Requirements

Adhere to relevant regulations when sending notifications:

  1. POPIA (South Africa)

    • Obtain explicit consent before sending marketing messages
    • Provide clear opt-out mechanisms in every message
    • Maintain records of consent
  2. GDPR (If dealing with EU users)

    • Document lawful basis for processing before sending notifications
    • Honor opt-out requests promptly
    • Limit data retention periods
  3. Industry-specific Requirements

    • Financial services notifications may have additional regulatory requirements
    • Healthcare notifications must comply with relevant privacy regulations

Next Steps