Notification Module Development for 1C-Bitrix
The standard \Bitrix\Main\Mail\Event::send() mechanism covers basic scenarios: an email after registration, an order confirmation. But as soon as the business wants push notifications, Telegram, WhatsApp, SMS — all with a unified delivery log, statuses, and retries — the built-in tooling runs out. Every new channel is connected differently, logs are scattered, and testing is painful.
Module Architecture
The vendor.notifications module is built on the concepts of a channel and an event. An event is something that happened in the system. A channel is a delivery method. One event can be dispatched through multiple channels simultaneously.
ORM tables:
-
b_vendor_notif_event— event types: id, code, name, description, default_channels (JSON), is_active -
b_vendor_notif_template— message templates: id, event_code, channel, subject, body, body_html, lang, variables_schema -
b_vendor_notif_queue— send queue: id, event_code, channel, recipient, payload (JSON), status (pending/sent/failed), attempts, created_at, sent_at, error -
b_vendor_notif_subscription— user subscriptions: id, user_id, event_code, channel, is_active
Delivery Channels
Each channel implements the ChannelInterface:
interface ChannelInterface
{
public function getName(): string;
public function send(Notification $notification): SendResult;
public function supports(string $recipient): bool;
}
Implementations:
-
EmailChannel — via
\Bitrix\Main\Mail\Mail::send()with custom SMTP settings or PHPMailer - SmsChannel — adapters for different providers (SMS.ru, SMSC, Twilio): unified interface, provider is a configuration parameter
-
TelegramChannel — Telegram Bot API,
sendMessagemethod, supports Markdown and inline buttons -
PushChannel — web push via the Web Push Protocol (
web-push-phplibrary), subscriptions stored inb_vendor_notif_push_subscription -
InternalChannel — in-site inbox notifications, stored in
b_vendor_notif_inbox, displayed on the site via AJAX
Event Dispatcher
Sending a notification from code is a single line:
\Vendor\Notifications\Dispatcher::dispatch('order_paid', [
'user_id' => $userId,
'order_id' => $orderId,
'order_sum' => $order->getPrice(),
'order_number' => $order->getField('ACCOUNT_NUMBER'),
]);
The dispatcher determines which channels to use (based on event settings), builds messages from templates, substitutes variables, and enqueues jobs into b_vendor_notif_queue.
Asynchronous Sending and Retries
Sending immediately at the moment of the event is bad practice: an HTTP request to Telegram can hang, blocking the order save operation. The queue is processed by a Bitrix agent:
// In the module installer
\CAgent::AddAgent(
'\Vendor\Notifications\QueueProcessor::run();',
'vendor.notifications',
'N',
60, // every 60 seconds
);
public static function run(): string
{
$items = NotifQueueTable::getList([
'filter' => ['STATUS' => 'pending', '<=ATTEMPTS' => 3],
'limit' => 50,
'order' => ['CREATED_AT' => 'ASC'],
])->fetchAll();
foreach ($items as $item) {
$channel = ChannelRegistry::get($item['CHANNEL']);
$result = $channel->send(Notification::fromQueue($item));
if ($result->isSuccess()) {
NotifQueueTable::update($item['ID'], ['STATUS' => 'sent', 'SENT_AT' => new DateTime()]);
} else {
NotifQueueTable::update($item['ID'], [
'ATTEMPTS' => $item['ATTEMPTS'] + 1,
'STATUS' => $item['ATTEMPTS'] >= 3 ? 'failed' : 'pending',
'ERROR' => $result->getError(),
]);
}
}
return '\Vendor\Notifications\QueueProcessor::run();';
}
After 3 failed attempts the job is set to failed status and appears in the dashboard for manual review.
User Subscription Management
In their personal account, users see a list of available events and can disable individual channels. Settings are stored in b_vendor_notif_subscription. Before enqueuing, the dispatcher checks whether the user has unsubscribed from this event type on this channel.
Templating
Message bodies are rendered via Twig. Variables are passed from the event payload. Templates support filters: |price for amount formatting, |date for localized dates. HTML emails support inline styles via Emogrifier.
Admin Interface
- Event list with default channel configuration
- Template editor with preview (test variable substitution)
- Send log with filtering by status, channel, date, recipient
- Delivery statistics by channel
- Test notification send to a specified address
Development Timeline
| Phase | Timeline |
|---|---|
| Architecture, ORM tables, channel interfaces | 2 days |
| Email and SMS channels | 2 days |
| Telegram and Push channels | 2 days |
| Internal notifications (inbox) | 1 day |
| Dispatcher, queue, retry agent | 2 days |
| User subscription management | 1 day |
| Templating (Twig + Emogrifier) | 1 day |
| Admin interface + send log | 2 days |
| Testing | 1 day |
Total: 14 working days. Adding extra channels (Viber, VK, WhatsApp Business API) — 1–2 days per channel.







