A comprehensive Laravel wrapper for Microsoft Graph API that provides an elegant, fluent interface for interacting with Microsoft 365 services including users, calendars, events, mail, and more.
- 🚀 Easy Integration - Simple, Laravel-style fluent API
- ⚡ Performance - Automatic OAuth token caching with expiry handling
- đź”’ Type Safe - Full support for PHP 8.2+ with strict types and return type declarations
- 🎯 Data Objects - Strongly-typed responses using Spatie Laravel Data
- 🛡️ Error Handling - Custom exceptions with clear, actionable error messages
- đź“§ Email & Calendar - Full support for Outlook, calendars, events, and mail
- 👥 User Management - Complete user CRUD operations with license management
- 🖼️ Profile Photos - Upload, download, and delete user profile photos
- 📎 Attachment Management - Upload, download, and manage file, item, and reference attachments
- 📝 Query Filters - OData query filtering for events and calendars
- đź”§ Laravel 10-12 - Supports Laravel 10.x, 11.x, and 12.x
- PHP 8.2 or higher
- Laravel 10.0, 11.0, or 12.0
- Microsoft Azure App Registration with appropriate permissions
Install the package via Composer:
composer require prasadchinwal/microsoft-graphPublish the configuration file:
php artisan vendor:publish --tag=microsoft-graph-configThis will create a config/microsoft-graph.php file in your application.
Before using this package, you need to register an application in the Azure Portal:
- Navigate to Azure Active Directory > App registrations
- Click New registration
- Give your app a name and select supported account types
- Click Register
- Note down the Application (client) ID and Directory (tenant) ID
- Go to Certificates & secrets > New client secret
- Create a new secret and note down its value
- Go to API permissions and add the required Microsoft Graph permissions:
User.Read.AllUser.ReadWrite.AllCalendars.ReadCalendars.ReadWriteMail.ReadMail.Send- Grant admin consent for your organization
Add the following to your .env file:
MICROSOFT_GRAPH_TENANT_ID=your-tenant-id
MICROSOFT_GRAPH_CLIENT_ID=your-client-id
MICROSOFT_GRAPH_CLIENT_SECRET=your-client-secretThe config/microsoft-graph.php file contains:
return [
'tenant_id' => env('MICROSOFT_GRAPH_TENANT_ID', null),
'client_id' => env('MICROSOFT_GRAPH_CLIENT_ID', null),
'client_secret' => env('MICROSOFT_GRAPH_CLIENT_SECRET', null),
'timezone' => env('APP_TIMEZONE', 'UTC'),
];Note: The package will validate configuration on boot and throw a ConfigurationException if required values are missing.
The package can be used via the Facade or by instantiating the class:
use PrasadChinwal\MicrosoftGraph\Facades\MicrosoftGraph;
// Via Facade
$graph = app('graph');
// Or direct instantiation
$graph = new \PrasadChinwal\MicrosoftGraph\MicrosoftGraph();Retrieve all users in your organization.
API Reference: List Users
use PrasadChinwal\MicrosoftGraph\Facades\MicrosoftGraph;
$users = MicrosoftGraph::users()->get();
foreach ($users as $user) {
echo $user->displayName . ' - ' . $user->mail;
}Retrieve a user by their email address (User Principal Name).
API Reference: Get User
$user = MicrosoftGraph::users()->find('john.doe@company.com');
echo $user->displayName; // John Doe
echo $user->jobTitle; // Software Engineer
echo $user->department; // Engineering
echo $user->mobilePhone; // +1 234 567 8900Update user properties using the User builder.
API Reference: Update User
use PrasadChinwal\MicrosoftGraph\Builder\User\User;
$userUpdate = new User();
$userUpdate->displayName = 'Jane Smith';
$userUpdate->jobTitle = 'Senior Software Engineer';
$userUpdate->department = 'Engineering';
$userUpdate->mobilePhone = '+1 234 567 8901';
MicrosoftGraph::users()->update('jane.smith@company.com', $userUpdate);Retrieve license details for a user.
API Reference: List License Details
$licenses = MicrosoftGraph::users()
->withEmail('john.doe@company.com')
->getLicenses();
foreach ($licenses as $license) {
echo $license->skuPartNumber;
foreach ($license->servicePlans as $plan) {
echo $plan->servicePlanName;
}
}Assign one or more licenses to a user.
API Reference: Assign License
use PrasadChinwal\MicrosoftGraph\Builder\License\AssignLicenseBuilder;
use PrasadChinwal\MicrosoftGraph\Builder\License\NewLicense;
use PrasadChinwal\MicrosoftGraph\Builder\License\NewLicenseCollection;
$license = new NewLicense();
$license->skuId = 'sku-guid-here';
$licenseCollection = new NewLicenseCollection([$license]);
$builder = new AssignLicenseBuilder(
addLicenses: $licenseCollection,
removeLicenses: []
);
$updatedUser = MicrosoftGraph::users()
->withEmail('john.doe@company.com')
->assignLicense($builder);Download a user's profile photo.
API Reference: Get Photo
$response = MicrosoftGraph::users()
->withEmail('john.doe@company.com')
->getPhoto();
// Save to file
file_put_contents('profile.jpg', $response->body());
// Or return as response
return response($response->body())
->header('Content-Type', 'image/jpeg');Upload a new profile photo for a user.
API Reference: Update Photo
$imageData = file_get_contents('/path/to/photo.jpg');
MicrosoftGraph::users()
->withEmail('john.doe@company.com')
->updatePhoto($imageData);Remove a user's profile photo.
API Reference: Delete Photo
MicrosoftGraph::users()
->withEmail('john.doe@company.com')
->deletePhoto();Retrieve all calendars for a user.
API Reference: List Calendars
$calendars = MicrosoftGraph::calendar()
->for('john.doe@company.com')
->get();
foreach ($calendars as $calendar) {
echo $calendar->name;
}Get free/busy schedule information for one or more users.
API Reference: Get Schedule
use Carbon\Carbon;
$users = ['john.doe@company.com', 'jane.smith@company.com'];
$schedule = MicrosoftGraph::calendar()
->for('requester@company.com')
->schedule(
users: $users,
from: Carbon::now(),
to: Carbon::now()->addDays(7),
timezone: 'America/Chicago',
interval: 60
);Get calendar events within a specific time range.
API Reference: List Calendar View
use Carbon\Carbon;
$events = MicrosoftGraph::calendar()
->for('john.doe@company.com')
->view(
start: Carbon::now()->toIso8601String(),
end: Carbon::now()->addMonth()->toIso8601String()
);Retrieve calendar events for a user.
API Reference: List Events
$events = MicrosoftGraph::event()
->for('john.doe@company.com')
->get();
foreach ($events as $event) {
echo $event->subject;
echo $event->start->dateTime;
echo $event->end->dateTime;
}Use OData filters to query specific events.
API Reference: Filter Query Parameter
// Get events within a date range
$events = MicrosoftGraph::event()
->for('john.doe@company.com')
->where('start/dateTime', 'ge', '2024-01-01')
->where('end/dateTime', 'le', '2024-12-31')
->get();
// Use OR conditions
$events = MicrosoftGraph::event()
->for('john.doe@company.com')
->where('subject', 'eq', 'Team Meeting')
->orWhere('subject', 'eq', 'All Hands')
->get();Create a new calendar event using a CalendarEvent class.
API Reference: Create Event
Step 1: Generate an event class:
php artisan make:graph-event TeamMeetingEventStep 2: Configure the event class:
<?php
namespace App\Mail;
use PrasadChinwal\MicrosoftGraph\Calendar\Event\CalendarEvent;
use PrasadChinwal\MicrosoftGraph\Calendar\Event\Eventable\Envelope;
use PrasadChinwal\MicrosoftGraph\Calendar\Event\Eventable\Attendee;
use PrasadChinwal\MicrosoftGraph\Calendar\Event\Eventable\Enums\CalendarEventImportance;
use Illuminate\Mail\Mailables\Content;
use Carbon\Carbon;
class TeamMeetingEvent extends CalendarEvent
{
public function envelope(): Envelope
{
return new Envelope(
from: 'organizer@company.com',
subject: 'Weekly Team Sync',
attendees: [
new Attendee('john.doe@company.com', 'John Doe', required: true),
new Attendee('jane.smith@company.com', 'Jane Smith', required: false),
],
start: Carbon::parse('2024-12-20 10:00:00'),
end: Carbon::parse('2024-12-20 11:00:00'),
location: 'Conference Room A',
importance: CalendarEventImportance::HIGH->value,
isOnlineMeeting: true,
reminder: true
);
}
public function content(): Content
{
return new Content(
markdown: 'emails.team-meeting',
with: ['agenda' => 'Sprint planning and retrospective']
);
}
}Step 3: Create the event:
use App\Mail\TeamMeetingEvent;
$response = MicrosoftGraph::event()->create(new TeamMeetingEvent());Update an existing calendar event.
API Reference: Update Event
$response = MicrosoftGraph::event()->update(
eventId: 'AAMkAGI2...',
mailable: new TeamMeetingEvent()
);Accept a meeting invitation.
API Reference: Accept Event
MicrosoftGraph::event()
->for('john.doe@company.com')
->accept(
eventId: 'AAMkAGI2...',
message: 'Looking forward to it!'
);Decline a meeting invitation.
API Reference: Decline Event
MicrosoftGraph::event()
->for('john.doe@company.com')
->decline(
eventId: 'AAMkAGI2...',
message: 'Unable to attend due to conflict.'
);Cancel a meeting (organizer only).
API Reference: Cancel Event
MicrosoftGraph::event()
->for('organizer@company.com')
->cancel(
eventId: 'AAMkAGI2...',
message: 'Meeting cancelled due to unforeseen circumstances.'
);Retrieve email messages for a user.
API Reference: List Messages
$messages = MicrosoftGraph::mail()
->for('john.doe@company.com')
->top(50)
->get();Apply OData filters to retrieve specific messages.
// Get unread messages
$messages = MicrosoftGraph::mail()
->for('john.doe@company.com')
->where('isRead', '!=', 'true')
->top(25)
->get();
// Get messages from a specific sender
$messages = MicrosoftGraph::mail()
->for('john.doe@company.com')
->where('from/emailAddress/address', '=', 'sender@example.com')
->get();
// Filter by received date
$messages = MicrosoftGraph::mail()
->for('john.doe@company.com')
->where('receivedDateTime', '>=', '2024-01-01T00:00:00Z')
->top(100)
->get();Send an email on behalf of a user.
API Reference: Send Mail
// Send to a single recipient
MicrosoftGraph::outlook()
->for('sender@company.com')
->sendEmail(
subject: 'Project Update',
message: 'The project is progressing well...',
to: 'recipient@company.com'
);
// Send to multiple recipients
MicrosoftGraph::outlook()
->for('sender@company.com')
->sendEmail(
subject: 'Team Announcement',
message: 'Please review the attached document...',
to: [
'john.doe@company.com',
'jane.smith@company.com',
'team@company.com'
]
);API Reference: User Team Configuration
use PrasadChinwal\MicrosoftGraph\Facades\MicrosoftGraph;
$data = MicrosoftGraph::teamConfiguration()
->where(field: 'id', operator: '=', value: '109c9587-bdf8-4f84-ba53-01c7ab2efa22')
->get();
dd($data->first()->telephoneNumbers->pluck('telephoneNumber'));Check is users Enterprise Voice is enabled:
use PrasadChinwal\MicrosoftGraph\Facades\MicrosoftGraph;
$data = MicrosoftGraph::teamConfiguration()
->where(field: 'id', operator: '=', value: '109c9587-bdf8-4f84-ba53-01c7ab2efa22')
->get();
dd($data->first()->hasEnterpriseVoiceEnabled());API Reference: List numberAssignments
use PrasadChinwal\MicrosoftGraph\Facades\MicrosoftGraph;
$data = MicrosoftGraph::numberAssignement()
// ->where(field: 'assignmentStatus', operator: '=', value: 'unassigned')
// ->where('telephoneNumber', '=', '+222222222')
->get();
dd($data);Microsoft Graph API supports three types of attachments:
- File Attachments - Binary files (up to 3MB)
- Item Attachments - Embedded contacts, events, or messages
- Reference Attachments - Links to files on OneDrive, Dropbox, etc.
Get all attachments for a message or event.
API Reference: List Attachments
// List message attachments
$attachments = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->list();
foreach ($attachments as $attachment) {
echo $attachment->name;
echo $attachment->contentType;
echo $attachment->size;
}
// List event attachments
$attachments = MicrosoftGraph::attachments()
->forEvent('john.doe@company.com', 'eventId')
->list();Retrieve metadata for a specific attachment.
API Reference: Get Attachment
$attachment = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->get('attachmentId');
echo $attachment->id;
echo $attachment->name;
echo $attachment->contentType;
echo $attachment->size;
echo $attachment->lastModifiedDateTime;Download the raw binary content of a file attachment.
$response = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->getRaw('attachmentId');
// Save to file
file_put_contents('downloaded_file.pdf', $response->body());
// Or return as HTTP response
return response($response->body())
->header('Content-Type', $response->header('Content-Type'));Upload a file attachment (up to 3MB).
API Reference: Add Attachment
From File Path:
use PrasadChinwal\MicrosoftGraph\Builder\Attachment\FileAttachmentBuilder;
// Create attachment from file
$builder = FileAttachmentBuilder::fromFile('/path/to/document.pdf');
$attachment = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->addFile($builder);
echo $attachment->id; // Use this ID for future operationsFrom Binary Data:
use PrasadChinwal\MicrosoftGraph\Builder\Attachment\FileAttachmentBuilder;
$imageData = file_get_contents('/path/to/image.jpg');
$builder = FileAttachmentBuilder::fromData(
data: $imageData,
name: 'profile-photo.jpg',
contentType: 'image/jpeg'
);
$attachment = MicrosoftGraph::attachments()
->forEvent('john.doe@company.com', 'eventId')
->addFile($builder);Inline Attachment (for emails):
use PrasadChinwal\MicrosoftGraph\Builder\Attachment\FileAttachmentBuilder;
$builder = FileAttachmentBuilder::fromFile('/path/to/logo.png')
->asInline('logo-cid');
$attachment = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'draftMessageId')
->addFile($builder);
// Reference in HTML body as: <img src="cid:logo-cid">Add a link to a file stored on OneDrive, Dropbox, or other cloud storage.
use PrasadChinwal\MicrosoftGraph\Builder\Attachment\ReferenceAttachmentBuilder;
$builder = ReferenceAttachmentBuilder::fromUrl(
url: 'https://contoso.sharepoint.com/documents/report.xlsx',
name: 'Q4 Financial Report'
)
->setProvider('oneDriveBusiness')
->setPermission('edit')
->setThumbnail('https://contoso.sharepoint.com/thumbnails/report_thumb.png');
$attachment = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->addReference($builder);Available Providers:
oneDriveBusinessoneDriveConsumerdropbox
Available Permissions:
view- Read-only accessedit- Read and write accessanonymousView- Public read-onlyanonymousEdit- Public read and writeorganizationView- Organization read-onlyorganizationEdit- Organization read and write
Add an attachment using custom array data for advanced scenarios.
$attachmentData = [
'@odata.type' => '#microsoft.graph.fileAttachment',
'name' => 'custom-document.txt',
'contentBytes' => base64_encode('Hello, World!'),
'contentType' => 'text/plain',
];
$attachment = MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->create($attachmentData);Remove an attachment from a message or event.
API Reference: Delete Attachment
MicrosoftGraph::attachments()
->forMessage('john.doe@company.com', 'messageId')
->delete('attachmentId');
// Or for events
MicrosoftGraph::attachments()
->forEvent('john.doe@company.com', 'eventId')
->delete('attachmentId');use PrasadChinwal\MicrosoftGraph\Builder\Attachment\FileAttachmentBuilder;
// 1. Create a draft message
$message = MicrosoftGraph::mail()->createDraft([
'subject' => 'Project Report',
'body' => [
'contentType' => 'HTML',
'content' => '<p>Please find attached the project report.</p>'
],
'toRecipients' => [
['emailAddress' => ['address' => 'manager@company.com']]
]
]);
// 2. Add attachments
$pdfBuilder = FileAttachmentBuilder::fromFile('/reports/project-report.pdf');
$excelBuilder = FileAttachmentBuilder::fromFile('/reports/data.xlsx');
MicrosoftGraph::attachments()
->forMessage('sender@company.com', $message['id'])
->addFile($pdfBuilder);
MicrosoftGraph::attachments()
->forMessage('sender@company.com', $message['id'])
->addFile($excelBuilder);
// 3. Send the message
MicrosoftGraph::mail()->send($message['id']);Important: The direct attachment API supports files up to 3MB. For larger files (3-150MB), use the upload session method:
// Files larger than 3MB throw an exception
try {
$builder = FileAttachmentBuilder::fromFile('/large-file.zip');
} catch (\InvalidArgumentException $e) {
// Handle large file - use upload session instead
// (Upload session not yet implemented in this package)
}| Type | Use Case | Max Size | Properties |
|---|---|---|---|
| fileAttachment | Documents, images, files | 3 MB | contentBytes, contentType, name |
| itemAttachment | Embedded contacts, events, messages | 3 MB | item (nested object) |
| referenceAttachment | OneDrive, SharePoint, Dropbox links | N/A | sourceUrl, providerType, permission |
The package includes custom exceptions for better error handling:
MicrosoftGraphException- Base exception classAuthenticationException- OAuth/token errorsInvalidEmailException- Invalid email formatConfigurationException- Missing or invalid configuration
use PrasadChinwal\MicrosoftGraph\Exceptions\InvalidEmailException;
use PrasadChinwal\MicrosoftGraph\Exceptions\ConfigurationException;
use Illuminate\Http\Client\RequestException;
try {
$user = MicrosoftGraph::users()->find('invalid-email');
} catch (InvalidEmailException $e) {
// Handle invalid email format
return response()->json(['error' => $e->getMessage()], 400);
} catch (ConfigurationException $e) {
// Handle configuration issues
Log::error('Microsoft Graph configuration error: ' . $e->getMessage());
return response()->json(['error' => 'Service unavailable'], 503);
} catch (RequestException $e) {
// Handle API request failures
Log::error('Microsoft Graph API error: ' . $e->getMessage());
return response()->json(['error' => 'External service error'], 502);
}The package automatically validates configuration on boot:
// If configuration is missing or invalid, a ConfigurationException will be thrown
// Example error messages:
// "Microsoft Graph configuration 'TENANT_ID' is not set. Please ensure MICROSOFT_GRAPH_TENANT_ID is set in your .env file."
// "Microsoft Graph configuration 'timezone' is invalid: Invalid timezone identifier"Access tokens are automatically cached with a 5-minute buffer before expiry. This significantly improves performance by preventing redundant OAuth requests.
To manually clear the token cache (useful for testing):
$graph = new MicrosoftGraph();
$graph->clearTokenCache();Set a custom timezone for calendar operations in your .env:
APP_TIMEZONE=America/New_YorkOr directly in the config file:
'timezone' => 'Europe/London',All responses are returned as strongly-typed Spatie Data objects:
$user = MicrosoftGraph::users()->find('john.doe@company.com');
// Full IDE autocomplete support
$user->displayName; // string
$user->accountEnabled; // bool
$user->businessPhones; // array
$user->interests; // array|nullThe package includes factories and helpers for testing. You can mock the Microsoft Graph API in your tests:
use Illuminate\Support\Facades\Http;
public function test_user_retrieval()
{
Http::fake([
'graph.microsoft.com/*' => Http::response([
'value' => [
[
'displayName' => 'Test User',
'mail' => 'test@example.com',
// ... other fields
]
]
], 200)
]);
$users = MicrosoftGraph::users()->get();
$this->assertCount(1, $users);
$this->assertEquals('Test User', $users->first()->displayName);
}Please see CHANGELOG for more information on what has changed recently.
Contributions are welcome! Please feel free to submit a Pull Request.
If you discover any security-related issues, please email the package author instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.
For support, please open an issue on GitHub or contact the maintainer.
- Microsoft Graph API Documentation: https://learn.microsoft.com/en-us/graph/
- Azure Portal: https://portal.azure.com
- Package Repository: https://github.com/prasadchinwal/microsoft-graph