Telegram-Benachrichtigungen für eine bestehende Laravel-Anwendung
Telegram ist der preiswerteste brauchbare Notification-Channel, den eine Laravel-Anwendung hinzufügen kann: Bot registrieren, die Chat-ID jedes Empfängers speichern, und ein Queue-Job POSTet JSON an den sendMessage-Endpunkt. Ein SDK braucht es nicht, einen Webhook für reine Zustellung ebensowenig, und die dokumentierten Limits (rund 30 Nachrichten pro Sekunde insgesamt, eine pro Sekunde pro Chat) sind Queue-Probleme mit Queue-Lösungen.
Was brauchst du, bevor die erste Nachricht geht?#
Zwei Werte und ein Einwilligungsschritt:
- Ein Bot-Token von @BotFather:
/newbot, sechzig Sekunden. - Die Chat-ID des Empfängers. Eine Person öffnet den Bot und drückt Start; die ID kommt mit jedem Update (in der Entwicklung zeigt
getUpdatessie direkt). Gruppen funktionieren genauso, ihre IDs sind negativ. - Der Einwilligungsschritt ist der entscheidende: Ein Bot kann einem Nutzer nicht schreiben, der ihn nie gestartet hat. Telegram erzwingt das, und es ist ohnehin die richtige Voreinstellung. Chat-IDs sind opt-in personenbezogene Daten; speichere und behandle sie so.
Der Channel in einer Klasse#
Laravels Notification-System nimmt einen eigenen Channel in etwa einem Dutzend Zeilen:
class TelegramChannel
{
public function send(object $notifiable, Notification $notification): void
{
$payload = $notification->toTelegram($notifiable);
$response = Http::asJson()->post(
'https://api.telegram.org/bot'.config('services.telegram.token').'/sendMessage',
[
'chat_id' => $payload->chatId,
'text' => $payload->text,
'parse_mode' => 'HTML',
'link_preview_options' => ['is_disabled' => true],
],
)->json();
if (! ($response['ok'] ?? false)) {
throw TelegramDelivery::failed($response['description'] ?? 'unknown error');
}
}
}Die Notification deklariert den Channel in via(), das notifiable Model stellt routeNotificationForTelegram() bereit und liefert die gespeicherte Chat-ID, die Queue-Verbindung macht den Rest. Mit parse_mode: HTML ist Escaping eigene Aufgabe: Nutzerdaten durch htmlspecialchars(), sonst stirbt die Nachricht an der ersten spitzen Klammer in einem Stack Trace.
Rate-Limits sind eine Queue-Frage, keine Channel-Frage#
Die Bot-API-FAQ nennt die Zahlen: nicht mehr als eine Nachricht pro Sekunde an denselben Chat, unter etwa 30 pro Sekunde beim Broadcast. Verstöße kommen als HTTP 429 mit einem retry_after-Wert zurück. Dort gehört er hin: in die Queue.
// inside the queued job, on a 429 response
$this->release($response['parameters']['retry_after'] ?? 5);Ein Report-Loop, der zweihundert Abonnenten benachrichtigt, sind zweihundert Queue-Jobs mit Jitter dazwischen, kein synchroner foreach. Dieselbe Disziplin gilt wie für jeden webhook-artigen Verkehr: Idempotente Worker, begrenzte Parallelität, ein Dead-Letter-Pfad, den ein Mensch tatsächlich liest.
Buttons machen aus Alarmen Workflows#
sendMessage nimmt ein InlineKeyboardMarkup. Ein Deploy-Hinweis mit Roll-back-Knopf, ein Bestellereignis mit Genehmigen und Ablehnen: Aus dem Zettel wird eine Aktion. URL-Buttons bleiben einwegig und brauchen keinen Webhook, ein Deep Link direkt ins Admin-Panel reicht oft.
Callback-Buttons sind eine andere Zusage: Die Drucke kommen als Callback-Queries an, der Bot braucht dann einen Webhook und einen idempotenten Handler. Ab dem Punkt baust du einen zweiseitigen Bot, und die Shop-Bot-Anatomie gilt, bevor man improvisiert.
Die Nachrichtenlänge ist auf 4096 Zeichen begrenzt. Lange Reports bewusst im Code splitten oder kürzen. „Bad Request: message is too long“ von der API ist Kürzung durch Absturz, das schlechteste von beiden.
Wo das seinen Wert zeigt#
Ich route Betriebssignale kleiner Systeme in eine Telegram-Gruppe statt in ein Monitoring-Produkt: Queue-Tiefe, fehlgeschlagene Job-Spitzen, nächtliche Backups, Bestellereignisse. Das Gruppenarchiv wird eine durchsuchbare Incident-Timeline, Emoji-Reaktionen funktionieren als Acknowledgment, und das Team hat die App ohnehin installiert. Für ein kleines Team ist das ein gut ausgegebenes Observability-Budget. Nachrichten sind die Zustellungsebene, nicht die Auswertungsebene: Wenn Metriken wichtiger werden als Nachrichten, weiter zu echtem Tooling und Telegram als Pager behalten.