Features
Notifications
Send email, SMS, and push notifications
Send multi-channel notifications with templates, retries, and delivery tracking.
Installation
composer require glueful/extensions-email-notification
Register in config/extensions.php
:
'providers' => [
Glueful\Extensions\EmailNotification\EmailNotificationServiceProvider::class,
],
Quick Start
use Glueful\Notifications\Services\NotificationService;
$notifications = app(NotificationService::class);
$notifications->send(
type: 'user.welcome',
notifiable: $user,
subject: 'Welcome to Glueful!',
data: [
'template' => 'welcome',
'name' => $user->name,
'cta_url' => 'https://app.example.com/get-started'
]
);
Minimal Notifiable Wrapper
If your user/entity does not implement Glueful\Notifications\Contracts\Notifiable
, wrap it with a tiny adapter:
namespace App\Notifications;
use Glueful\Notifications\Contracts\Notifiable;
class UserNotifiable implements Notifiable
{
public function __construct(
private string $uuid,
private string $email
) {}
public function routeNotificationFor(string $channel): ?string
{
// Map channel to recipient. Extend for SMS, push, etc.
return $channel === 'email' ? $this->email : null;
}
public function getNotifiableId(): string
{
return $this->uuid;
}
public function getNotifiableType(): string
{
return 'user';
}
}
// Usage
use Glueful\Notifications\Services\NotificationService;
$notifiable = new \App\Notifications\UserNotifiable($user['uuid'], $user['email']);
app(NotificationService::class)->send(
type: 'user.welcome',
notifiable: $notifiable,
subject: 'Welcome!',
data: ['template' => 'welcome', 'name' => $user['name']]
);
Basic Email
Send Welcome Email
public function register()
{
// Create user
$user = $this->getConnection()->table('users')->insert($data);
// Send welcome email
$notifications = app(\Glueful\Notifications\Services\NotificationService::class);
$notifications->send(
type: 'user.welcome',
notifiable: $user,
subject: 'Welcome!',
data: [
'template' => 'welcome',
'name' => $user->name
]
);
return Response::created($user);
}
Send with Custom Data
$notifications->send(
type: 'order.confirmation',
notifiable: $user,
subject: 'Order #' . $orderId,
data: [
'template' => 'order-confirmation',
'order_id' => $orderId,
'total' => $total,
'items' => $items,
'shipping_address' => $address
]
);
Templates
Create Email Template
templates/html/welcome.html
:
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.button { background: #007bff; color: white; padding: 12px 24px; }
</style>
</head>
<body>
<h1>Welcome, {{name}}!</h1>
<p>Thanks for joining Glueful. Get started now:</p>
<a href="{{cta_url}}" class="button">Get Started</a>
</body>
</html>
Use Template
$notifications->send(
type: 'user.welcome',
notifiable: $user,
subject: 'Welcome!',
data: [
'template' => 'welcome', // Matches welcome.html
'name' => $user->name,
'cta_url' => 'https://app.example.com'
]
);
Built-in Templates
Glueful includes these templates:
welcome
- Welcome new usersverification
- Email verificationpassword-reset
- Password reset linkalert
- System alertsdefault
- Generic template
Scheduled Notifications
Send notifications later:
$notifications->send(
type: 'reminder',
notifiable: $user,
subject: 'Don't forget!',
data: ['template' => 'reminder'],
options: [
'schedule' => new DateTime('+1 day')
]
);
Priority
Set notification priority:
$notifications->send(
type: 'urgent.alert',
notifiable: $user,
subject: 'Action Required',
data: ['template' => 'alert'],
options: [
'priority' => 'high' // high, normal, low
]
);
Retries
Automatic retries on failure:
// Configure retries
'retry' => [
'enabled' => true,
'delay' => 300, // 5 minutes
'backoff' => 'exponential',
'max_attempts' => 3
],
Backoff strategies:
exponential
: delay × 2^(attempt-1)linear
: delay × attemptfixed
: same delay every time
Common Patterns
Welcome Email
public function register()
{
$user = $this->db->table('users')->insert([
'name' => $data['name'],
'email' => $data['email'],
'password' => password_hash($data['password'], PASSWORD_DEFAULT)
]);
$notifications->send(
type: 'user.registered',
notifiable: $user,
subject: 'Welcome to ' . config('app.name'),
data: [
'template' => 'welcome',
'name' => $user->name,
'verify_url' => url('/verify/' . $user->verification_token)
]
);
return Response::created($user);
}
Password Reset
public function forgotPassword()
{
$email = $this->request->input('email');
$user = $this->getConnection()->table('users')->where(['email' => $email])->first();
if (!$user) {
return Response::success(null, 'If email exists, reset link sent');
}
$token = bin2hex(random_bytes(32));
$this->getConnection()->table('password_resets')->insert([
'email' => $email,
'token' => hash('sha256', $token),
'created_at' => date('Y-m-d H:i:s')
]);
$notifications = app(\Glueful\Notifications\Services\NotificationService::class);
$notifications->send(
type: 'password.reset',
notifiable: $user,
subject: 'Reset Your Password',
data: [
'template' => 'password-reset',
'name' => $user->name,
'reset_url' => url('/reset-password/' . $token)
]
);
return Response::success(null, 'Password reset link sent');
}
Order Confirmation
public function placeOrder()
{
$order = $this->getConnection()->table('orders')->insert($orderData);
$user = $this->getConnection()->table('users')->find($order->user_id);
$notifications = app(\Glueful\Notifications\Services\NotificationService::class);
$notifications->send(
type: 'order.placed',
notifiable: $user,
subject: 'Order Confirmation #' . $order->id,
data: [
'template' => 'order-confirmation',
'order_id' => $order->id,
'total' => $order->total,
'items' => $this->getOrderItems($order->id),
'tracking_url' => url('/orders/' . $order->uuid)
]
);
return Response::created($order);
}
Digest Notifications
public function sendWeeklyDigest()
{
$users = $this->getConnection()->table('users')
->where(['digest_enabled' => true])
->get();
$notifications = app(\Glueful\Notifications\Services\NotificationService::class);
foreach ($users as $user) {
$stats = $this->getUserStats($user->id);
$notifications->send(
type: 'digest.weekly',
notifiable: $user,
subject: 'Your Weekly Summary',
data: [
'template' => 'weekly-digest',
'name' => $user->name,
'stats' => $stats,
'highlights' => $this->getHighlights($user->id)
]
);
}
}
Queue Notifications
Queue expensive notifications:
'queue' => [
'enabled' => true,
'queue_name' => 'emails',
'max_attempts' => 3
],
Notification Events
Listen to notification lifecycle:
use Glueful\Notifications\Events\NotificationSent;
use Glueful\Notifications\Events\NotificationFailed;
Event::listen(NotificationSent::class, function($event) {
logger()->info('Notification sent', [
'type' => $event->type,
'channel' => $event->channel
]);
});
Event::listen(NotificationFailed::class, function($event) {
logger()->error('Notification failed', [
'type' => $event->type,
'error' => $event->error
]);
});
Configuration
config/email-notification.php
:
return [
'templates' => [
'extension_path' => __DIR__ . '/../templates/html',
'extension_mappings' => [
'welcome' => 'welcome',
'password-reset' => 'password-reset',
'verification' => 'verification',
'alert' => 'alert',
'default' => 'default'
],
'processing' => [
'minify_html' => env('MAIL_MINIFY_HTML', false),
'inline_css' => env('MAIL_INLINE_CSS', true),
'auto_text_version' => true
]
],
'queue' => [
'enabled' => env('MAIL_QUEUE_ENABLED', true),
'queue_name' => env('MAIL_QUEUE_NAME', 'emails'),
'max_attempts' => env('MAIL_QUEUE_MAX_ATTEMPTS', 3)
],
'retry' => [
'enabled' => env('MAIL_RETRY_ENABLED', true),
'delay' => env('MAIL_RETRY_DELAY', 300),
'backoff' => env('MAIL_RETRY_BACKOFF', 'exponential')
]
];
Best Practices
Use Queues
// ✅ Good - queued
'queue' => ['enabled' => true]
// ❌ Bad - blocks response
'queue' => ['enabled' => false]
Personalize
// ✅ Good - personal
"Hi {$user->name}, your order is ready!"
// ❌ Bad - generic
"Your order is ready."
Clear CTAs
// ✅ Good - clear action
<a href="{{verify_url}}">Verify Your Email</a>
// ❌ Bad - unclear
<a href="{{url}}">Click here</a>
Unsubscribe Links
// Always include
<p>
<a href="{{unsubscribe_url}}">Unsubscribe</a>
</p>
Testing
Test notifications without sending:
public function testWelcomeEmail()
{
$user = factory(User::class)->create();
$result = app(\Glueful\Notifications\Services\NotificationService::class)->send(
type: 'user.welcome',
notifiable: $user,
subject: 'Welcome!',
data: ['template' => 'welcome', 'name' => $user->name]
);
$this->assertEquals('success', $result['status']);
}
Troubleshooting
Emails not sending?
- Check SMTP configuration in
.env
- Verify queue worker is running
- Check
failed_jobs
table
Template not found?
- Verify template file exists
- Check template mapping in config
- Ensure template name matches
High failure rate?
- Check SMTP credentials
- Verify email addresses are valid
- Review rate limits
Extending Channels
Add SMS, push, or other channels:
namespace App\Channels;
class SmsChannel
{
public function send($notifiable, $data): array
{
$phone = $notifiable->phone_number;
$message = $data['message'];
// Send SMS via provider
$response = $this->smsProvider->send($phone, $message);
return [
'status' => $response->success ? 'success' : 'failed'
];
}
}
Register channel:
$channelManager->register('sms', new SmsChannel());
Next Steps
- Queues & Jobs - Queue notifications
- Events - Event-driven notifications
- Templates - Advanced templates