ejtj3/teams
Simple PHP 7.2+ connector for sending Microsoft Teams messages via Incoming Webhooks. Build and send MessageCards with fluent syntax: add text, title, theme color, sections with facts/images, and interactive actions/inputs. Includes Symfony bundle option.
composer require ejtj3/teams
use EJTJ3\Teams\Card;
use EJTJ3\Teams\Client;
$client = new Client('YOUR_WEBHOOK_URL');
$card = (new Card('Hello Teams!'))
->setText('This is a test message from Laravel.');
$client->send($card);
Trigger a notification when a GitHub Actions workflow completes:
// In your Laravel job or event listener
public function handle()
{
$client = new Client(config('teams.webhook_url'));
$card = (new Card('Build Status'))
->setText('Pipeline completed with ' . $this->status)
->setThemeColor($this->status === 'success' ? Card::STATUS_SUCCESS : Card::STATUS_CRITICAL);
$client->send($card);
}
Use a builder pattern for reusable card templates:
// app/Services/TeamsCardBuilder.php
class TeamsCardBuilder
{
public static function buildAlert(string $title, string $message, string $status): Card
{
return (new Card($title))
->setText($message)
->setThemeColor(self::mapStatusToColor($status))
->addSection((new Section($message))
->addFact('Status', $status)
->addFact('Time', now()->format('Y-m-d H:i:s')));
}
private static function mapStatusToColor(string $status): string
{
return match ($status) {
'critical' => Card::STATUS_CRITICAL,
'warning' => Card::STATUS_WARNING,
default => Card::STATUS_SUCCESS,
};
}
}
Usage:
TeamsCardBuilder::buildAlert('Server Alert', 'High CPU usage detected', 'warning');
For approval workflows, use ActionCard with HttpPostAction:
// app/Services/ApprovalCardBuilder.php
class ApprovalCardBuilder
{
public static function buildApproval(string $title, string $description, string $callbackUrl): Card
{
$card = (new Card($title))
->setText($description);
$actionCard = (new ActionCard('Approve/Reject'))
->addAction(new HttpPostAction('Approve', $callbackUrl . '?action=approve'))
->addAction(new HttpPostAction('Reject', $callbackUrl . '?action=reject'));
$card->addPotentialAction($actionCard);
return $card;
}
}
Handle Callback in Laravel:
// routes/web.php
Route::post('/teams/callback', function (Request $request) {
$action = $request->query('action');
// Process approval/rejection logic
});
Fetch data from Laravel models and populate sections:
// In a controller or service
$section = (new Section('New User Created'))
->setActivityTitle('User Registration')
->addFact('Name', $user->name)
->addFact('Email', $user->email)
->addFact('Role', $user->role);
$card->addSection($section);
Register the Client in AppServiceProvider:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(TeamsClient::class, function () {
return new Client(config('teams.webhook_url'));
});
}
Usage in Controllers:
use Illuminate\Support\Facades\App;
public function notify(TeamsClient $client)
{
$client->send((new Card('Test'))->setText('Hello from Laravel!'));
}
Avoid blocking requests by queuing webhook sends:
// app/Jobs/SendTeamsNotification.php
class SendTeamsNotification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle(TeamsClient $client)
{
$client->send($this->card);
}
}
Dispatch:
SendTeamsNotification::dispatch($card)->onQueue('teams');
Define webhook URLs in config/teams.php:
return [
'webhook_url' => env('TEAMS_WEBHOOK_URL'),
'default_theme' => \EJTJ3\Teams\Card::STATUS_DEFAULT,
];
Access via config('teams.webhook_url').
Trigger notifications on Laravel events (e.g., created, updated):
// app/Listeners/SendUserRegisteredNotification.php
public function handle(UserRegistered $event)
{
$card = (new Card('New User Registered'))
->addSection((new Section('Details'))
->addFact('Name', $event->user->name)
->addFact('Email', $event->user->email));
SendTeamsNotification::dispatch($card);
}
Mock the Client in PHPUnit:
// tests/Feature/TeamsNotificationTest.php
public function test_notification_is_sent()
{
$mock = Mockery::mock(TeamsClient::class);
$mock->shouldReceive('send')->once();
$this->app->instance(TeamsClient::class, $mock);
// Trigger event or controller
$this->assertTrue(true); // Mock verified
}
While the package doesn’t natively support adaptive cards, you can embed JSON payloads:
$client->send(json_encode([
'@type' => 'MessageCard',
'@context' => 'http://schema.org/extensions',
'themeColor' => '0076D7',
'sections' => [[
'activityTitle' => 'Hello world!',
'activitySubtitle' => 'Sub-title here',
'text' => 'This is a plain-text section.',
]],
]));
Store multiple webhook URLs and route dynamically:
// app/Services/MultiTeamsClient.php
class MultiTeamsClient
{
public function __construct(private array $webhookUrls) {}
public function sendToAll(Card $card)
{
foreach ($this->webhookUrls as $url) {
(new Client($url))->send($card);
}
}
}
Usage:
$client = new MultiTeamsClient(config('teams.channels'));
$client->sendToAll($card);
Handle transient failures with retries:
// app/Services/ResilientTeamsClient.php
class ResilientTeamsClient
{
public function sendWithRetry(Card $card, int $retries = 3): bool
{
$client = new Client(config('teams.webhook_url'));
$attempts = 0;
while ($attempts < $retries) {
try {
$client->send($card);
return true;
} catch (Exception $e) {
$attempts++;
if ($attempts === $retries) throw $e;
sleep(2 ** $attempts); // Exponential backoff
}
}
return false;
}
}
Webhook URL Validation:
trustedproxy middleware or reverse proxy like Nginx).Payload Size Limits:
Character Encoding:
Rate Limiting:
Deprecated Methods:
How can I help you explore Laravel packages today?