Messaging
The Messaging
module provides a powerful system for composing, targeting, and sending bulk messages to different groups within the school community. It is designed for asynchronous sending via a background worker.
Constructor
Creates a new Messaging module instance with database access, event system, and mail service integration.
Parameters
$db | Database | Yes | Database connection instance |
$events | Events | Yes | Event system for message notifications |
$mail | Mail | Yes | Mail service for sending messages |
Example
<?php
$config = [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=schoolkit;charset=utf8mb4',
'user' => 'your_username',
'pass' => 'your_password'
],
'storage_path' => __DIR__ . '/storage'
];
$schoolKit = SchoolKit::start($config);
$messaging = $schoolKit->messaging();
// Messaging module is now ready for bulk communication
echo "Messaging module initialized successfully";
?>
Quick Reference
Adds targeting criteria to specify message recipients
Resolves targets into concrete list of email addresses and returns count
Schedules message for delivery at specific time
Marks message for immediate sending by background worker and returns count
Workflow
- Create a Message: Use
create()
to compose the subject and body. - Define Recipients: Use
addTarget()
to specify who should receive the message (e.g., a whole grade, a specific class). - Expand Recipients: Use
expandRecipients()
to resolve the targets into a concrete list of email addresses. - Schedule or Send: Use
schedule()
orsendNow()
to mark the message for delivery by the background worker.
Template Management
Creates a reusable message template with separate HTML and text content for consistent communications.
Example
<?php
$templateId = $schoolKit->messaging()->createTemplate(
'Field Trip Reminder',
'Upcoming Field Trip - {{trip_date}}',
'Field Trip Reminder
Dear {{guardian_name}}, your child {{student_name}} has a field trip on {{trip_date}}.
',
"Dear {{guardian_name}}, your child {{student_name}} has a field trip on {{trip_date}}.",
123 // User ID of template creator
);
echo "Created template with ID: {$templateId}";
?>
Parameters
string $name
- The template name for identificationstring $subject
- The email subject line template?string $bodyHtml
- The HTML version of the email body (optional)?string $bodyText
- The plain text version of the email body (optional)?int $createdBy
- User ID of the template creator (optional)
Returns
int
- The ID of the newly created template
Lists available message templates with optional filtering.
Example
<?php
// Get templates created by a specific user
$templates = $schoolKit->messaging()->listTemplates(['created_by' => 123]);
// Get all templates
$allTemplates = $schoolKit->messaging()->listTemplates();
foreach ($templates as $template) {
echo "Template: {$template['name']} - Subject: {$template['subject']}\n";
}
?>
Parameters
array $filters
- Optional filters (created_by, name, type, etc.)
Returns
array
- Array of template records
Permanently deletes a message template.
Example
<?php
if ($schoolKit->messaging()->deleteTemplate(15)) {
echo "Template deleted successfully";
} else {
echo "Failed to delete template";
}
?>
Parameters
int $templateId
- The ID of the template to delete
Returns
bool
- True on successful deletion, false otherwise
Message Composition
Creates a new message draft.
Parameters
Name | Type | Required | Description |
---|---|---|---|
$data |
array |
Yes | Associative array with subject , and either body_html or body_text . |
Returns
The ID of the newly created message.
Example
<?php
$messageId = $schoolKit->messaging()->create([
'subject' => 'School Picture Day Reminder',
'body_html' => 'Don\'t forget, picture day is this Friday!
',
'created_by' => 123 // Admin user ID
]);
echo "Created message draft with ID: {$messageId}";
?>
Adds a recipient group to the message. Valid scope types are: class
, grade
, activity
.
Parameters
Name | Type | Required | Description |
---|---|---|---|
$messageId | int | Yes | The ID of the message. |
$scopeType | string | Yes | Type of target group (class, grade, activity). |
$scopeId | string | Yes | ID of the target group. |
Returns
bool
- True on success, false otherwise.
Example
<?php
$messageId = 101;
// Target all guardians of students in grade 5
$schoolKit->messaging()->addTarget($messageId, 'grade', '5');
// Also target all guardians of students in the chess club (activity ID 22)
$schoolKit->messaging()->addTarget($messageId, 'activity', '22');
?>
Adds a single, manual email address to the message recipients.
Example
<?php
$messageId = 101;
$schoolKit->messaging()->addManual($messageId, 'special.guest@example.com', 'Special Guest');
$schoolKit->messaging()->addManual($messageId, 'board.member@school.edu', 'Board Member');
echo "Added manual recipients to the message";
?>
Parameters
int $messageId
- The ID of the messagestring $email
- The email address to addstring $name
- Optional display name for the recipient
Returns
bool
- True on successful addition, false otherwise
Attaches a file to a message for delivery to all recipients.
Example
<?php
$messageId = 101;
// Attach a PDF with custom name
$schoolKit->messaging()->attach($messageId, '/uploads/permission_slip.pdf', 'Permission Slip.pdf');
// Attach an image (MIME type auto-detected)
$schoolKit->messaging()->attach($messageId, '/uploads/school_map.png');
echo "Files attached to message";
?>
Parameters
int $messageId
- The ID of the messagestring $filePath
- Path to the file to attach?string $name
- Optional display name for the attachment?string $mime
- Optional MIME type (auto-detected if not provided)
Returns
bool
- True on successful attachment, false otherwise
Sending & Scheduling
Resolves all targets (like grades and classes) into a final list of individual email recipients. This should be done before sending.
Parameters
Name | Type | Required | Description |
---|---|---|---|
$messageId | int | Yes | The ID of the message. |
Returns
The number of unique recipients added to the queue.
Example
<?php
$messageId = 101;
$count = $schoolKit->messaging()->expandRecipients($messageId);
echo "Message is ready to be sent to {$count} recipients.";
?>
Marks a message to be sent as soon as possible by the background worker.
Parameters
Name | Type | Required | Description |
---|---|---|---|
$messageId | int | Yes | The ID of the message to send. |
Returns
The number of pending recipients for this message.
Example
<?php
$messageId = 101;
$pendingCount = $schoolKit->messaging()->sendNow($messageId);
echo "Message queued for immediate delivery to {$pendingCount} recipients.";
?>
Schedules a message to be sent at a future time by the background worker.
Parameters
Name | Type | Required | Description |
---|---|---|---|
$messageId | int | Yes | The ID of the message to schedule. |
$sendAt | string | Yes | A valid date-time string (e.g., '2025-09-01 09:00:00'). |
Returns
bool
- True on success, false otherwise.
Example
<?php
$messageId = 101;
$schoolKit->messaging()->schedule($messageId, '2025-08-30 17:00:00');
echo "Message scheduled for delivery.";
?>
Gets the delivery status counts for a message.
Example
<?php
$status = $schoolKit->messaging()->status(101);
echo "Message Status:\n";
echo "Total Recipients: {$status['totals']}\n";
echo "Sent: {$status['sent']}\n";
echo "Failed: {$status['failed']}\n";
echo "Pending: {$status['pending']}\n";
?>
Parameters
int $messageId
- The ID of the message to check
Returns
array
- Status counts with keys: totals, sent, failed, pending
Performs a dry run simulation to preview who would receive a message without actually sending it.
Example
<?php
$dryRunResults = $schoolKit->messaging()->dryRun(101);
echo "Subject: {$dryRunResults['subject']}\n";
echo "Would send to " . count($dryRunResults['to']) . " recipients:\n";
foreach ($dryRunResults['to'] as $email) {
echo "• {$email}\n";
}
if (isset($dryRunResults['preview_html'])) {
echo "\nHTML Preview:\n{$dryRunResults['preview_html']}\n";
}
if (isset($dryRunResults['preview_text'])) {
echo "\nText Preview:\n{$dryRunResults['preview_text']}\n";
}
?>
Parameters
int $messageId
- The ID of the message to test
Returns
array
- Dry run results with keys: 'subject', 'to' (array of emails), 'preview_html' (optional), 'preview_text' (optional)
Permanently unsubscribes an email address from receiving bulk messages.
Example
<?php
$email = $_GET['email'] ?? '';
$token = $_GET['token'] ?? '';
// Verify unsubscribe token first for security
if (hash_equals($expected_token, $token)) {
if ($schoolKit->messaging()->unsubscribe($email)) {
echo "You have been successfully unsubscribed from bulk messages";
} else {
echo "Unable to process unsubscribe request";
}
} else {
echo "Invalid unsubscribe link";
}
?>
Parameters
string $email
- The email address to unsubscribe
Returns
bool
- True on successful unsubscription, false otherwise
Worker Methods
These methods are intended for use by the background sending script (e.g., bin/send.php
).
Gets all messages that are due for sending and have pending recipients (used by background workers).
Example
<?php
// Background worker script
$pendingMessages = $schoolKit->messaging()->getPendingMessages();
foreach ($pendingMessages as $message) {
echo "Processing message ID: {$message['id']} - '{$message['subject']}'\n";
// Process recipients for this message
$recipients = $schoolKit->messaging()->getPendingRecipients($message['id'], 25);
// ... send emails to recipients
}
?>
Returns
array
- Array of message records ready for processing by the worker
Gets a batch of pending recipients for a specific message (used by background workers).
Example
<?php
$recipients = $schoolKit->messaging()->getPendingRecipients(101, 25);
foreach ($recipients as $recipient) {
// Attempt to send email
try {
$schoolKit->mail()->send([
'to' => $recipient['email'],
'subject' => $recipient['subject'],
'html' => $recipient['body_html']
]);
$schoolKit->messaging()->markSent($recipient['id']);
} catch (Exception $e) {
$schoolKit->messaging()->markFailed($recipient['id'], $e->getMessage());
}
}
?>
Parameters
int $messageId
- The ID of the messageint $limit
- Maximum number of recipients to fetch (default: 50)
Returns
array
- Array of recipient records ready for sending
Marks a recipient's delivery status as 'sent' (used by background workers).
Example
<?php
// After successfully sending an email
if ($schoolKit->messaging()->markSent($recipientId)) {
echo "Recipient marked as sent";
} else {
echo "Failed to update recipient status";
}
?>
Parameters
int $recipientId
- The ID of the recipient record
Returns
bool
- True on successful status update, false otherwise
Marks a recipient's delivery status as 'failed' and logs the error (used by background workers).
Example
<?php
// After a failed email send attempt
if ($schoolKit->messaging()->markFailed($recipientId, "SMTP connection timeout")) {
echo "Recipient marked as failed with error logged";
} else {
echo "Failed to update recipient status";
}
?>
Parameters
int $recipientId
- The ID of the recipient recordstring $error
- The error message to log
Returns
bool
- True on successful status update, false otherwise
Retrieves all attachments for a specific message (used by background workers).
Example
<?php
$attachments = $schoolKit->messaging()->getMessageAttachments(101);
foreach ($attachments as $attachment) {
echo "File: {$attachment['name']} ({$attachment['mime']})\n";
echo "Path: {$attachment['file_path']}\n";
echo "Size: " . number_format($attachment['size'] / 1024, 2) . " KB\n";
}
?>
Parameters
int $messageId
- The ID of the message
Returns
array
- Array of attachment records with file paths, names, and MIME types
Determines whether a failed recipient should be retried based on failure reason and retry count (used by background workers).
Example
<?php
// Background worker logic
$recipients = $schoolKit->messaging()->getPendingRecipients(101, 25);
foreach ($recipients as $recipient) {
try {
// Attempt to send email
$sent = $schoolKit->mail()->send([
'to' => $recipient['email'],
'subject' => $recipient['subject'],
'html' => $recipient['body_html']
]);
if ($sent) {
$schoolKit->messaging()->markSent($recipient['id']);
} else {
throw new Exception("SMTP failed");
}
} catch (Exception $e) {
// Check if we should retry this recipient
if ($schoolKit->messaging()->shouldRetry($recipient)) {
// Will be retried in next worker cycle
continue;
} else {
// Mark as permanently failed
$schoolKit->messaging()->markFailed($recipient['id'], $e->getMessage());
}
}
}
?>
Parameters
array $recipient
- The recipient record containing status and retry information
Returns
bool
- True if the recipient should be retried, false if permanently failed
Marks multiple recipients as sent in a single batch operation (used by background workers).
Example
<?php
// After successfully sending multiple emails
$sentIds = [123, 124, 125, 126];
$success = $schoolKit->messaging()->markSentBatch($sentIds);
if ($success) {
echo "All recipients marked as sent successfully";
} else {
echo "Some recipients could not be marked as sent";
}
?>
Parameters
array $recipientIds
- Array of recipient IDs to mark as sent
Returns
bool
- True if all recipients were successfully updated, false otherwise
Marks multiple recipients as failed with their respective error messages in a single batch operation (used by background workers).
Example
<?php
// After multiple failed email attempts
$failures = [
['id' => 127, 'error' => 'Invalid email address'],
['id' => 128, 'error' => 'SMTP timeout'],
['id' => 129, 'error' => 'Recipient blocked']
];
$success = $schoolKit->messaging()->markFailedBatch($failures);
if ($success) {
echo "All recipients marked as failed successfully";
} else {
echo "Some recipients could not be marked as failed";
}
?>
Parameters
array $failures
- Array of recipient data with 'id' and 'error' keys
Returns
bool
- True if all recipients were successfully updated, false otherwise
All Available Methods
Constructor
- __construct($db, $events, $mail) - Initialize Messaging module
Template Management (3 methods)
- createTemplate() - Creates reusable message templates
- listTemplates() - Lists available message templates
- deleteTemplate() - Permanently deletes a template
Message Composition (4 methods)
- create() - Creates a new message draft
- addTarget() - Adds recipient groups to message
- addManual() - Adds individual email addresses
- attach() - Attaches files to messages
Sending & Scheduling (6 methods)
- expandRecipients() - Resolves targets to recipient list
- sendNow() - Marks message for immediate sending
- schedule() - Schedules message for future delivery
- status() - Gets message delivery status
- dryRun() - Previews message recipients
- unsubscribe() - Unsubscribes email addresses
Worker Methods (7 methods)
- getPendingMessages() - Gets messages ready for sending
- getPendingRecipients() - Gets recipient batches for processing
- markSent() - Marks individual recipients as sent
- markFailed() - Marks individual recipients as failed
- getMessageAttachments() - Retrieves message attachments
- shouldRetry() - Determines if recipient should be retried
- markSentBatch() - Marks multiple recipients as sent
- markFailedBatch() - Marks multiple recipients as failed
Total: 22 methods documented (including constructor)