Download the PHP package innoge/laravel-msgraph-mailbox without Composer
On this page you can find all versions of the php package innoge/laravel-msgraph-mailbox. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download innoge/laravel-msgraph-mailbox
More information about innoge/laravel-msgraph-mailbox
Files in innoge/laravel-msgraph-mailbox
Package laravel-msgraph-mailbox
Short Description Observe Microsoft 365 mailboxes via Microsoft Graph change notifications and delta queries, and act on their messages
License MIT
Homepage https://github.com/innoge/laravel-msgraph-mailbox
Informations about the package laravel-msgraph-mailbox
Laravel Microsoft Graph Mailbox
- Introduction
- Installation
- Registering the Entra App
- Configuring Mailboxes
- Going Live
- Scheduling the Commands Yourself
- Registering the Webhook Route Yourself
- Receiving Messages
- Working With Messages
- Reading Messages
- Attachments
- Organizing Messages
- Queued Actions
- A Complete Example
- Testing
- How It Works
- Local Development
- Security
Introduction
Plenty of applications have a shared Microsoft 365 mailbox somewhere next to them: a support inbox, an invoices mailbox, a "reply to this email" address. Laravel Microsoft Graph Mailbox turns those mailboxes into Laravel events. When a message arrives, your listener receives it, and you can read it, store its attachments and archive it, all with a few lines of familiar Laravel code:
Some things you might build with it:
- Support desks that turn incoming mail into tickets and attach replies to the right ticket.
- Document intake that stores invoices, delivery notes or applications from a mailbox in your storage.
- Mailbox automation that routes, flags, categorizes or archives mail based on your own rules.
- Bounce and out-of-office handling that marks addresses as unreachable.
- CRM activity logs that record every email a customer sends you.
Under the hood, the package listens to Microsoft Graph change notifications, so messages reach your application within seconds, and a scheduled delta sync guarantees nothing is lost when a notification is missed.
Installation
The package requires PHP 8.3+ and Laravel 12.53+ or 13. Install it with Composer, then run the install command. It
publishes the configuration file and the migration, adds the credential variables to your .env file and asks which
mailbox you'd like to observe:
The package uses the Microsoft Graph client of innoge/laravel-msgraph-mail. You don't have to use its mail driver, but if you do, both packages share the same credentials.
Registering the Entra App
The package authenticates as a Microsoft Entra app with an application permission. If you already send mail with
innoge/laravel-msgraph-mail, you can use the same app and simply add the permission.
- In the Entra admin center, go to App registrations and create a new registration. Note the Application (client) ID and the Directory (tenant) ID.
- Under Certificates & secrets, create a client secret, or upload a certificate if you'd rather not rotate secrets.
- Under API permissions, add the Microsoft Graph application permission
Mail.ReadWriteand grant admin consent. If you only observe mailboxes and never act on messages,Mail.Readis enough. - Limit the app to the mailboxes it should see. An application permission covers every mailbox in your tenant by default, so restrict it with RBAC for Applications or an Application Access Policy:
Then add the credentials to your .env file:
Configuring Mailboxes
Tell the package which mailboxes to observe in config/msgraph-mailbox.php. A plain address observes the inbox:
Use the mailbox's primary SMTP address rather than an alias, since Microsoft reports senders by their primary address. If you need more control, you may choose the folders and the events of each mailbox:
Folders are WellKnownFolder cases or display name paths. If a folder doesn't exist, the package tells you instead of
silently observing nothing.
Mailboxes From Your Database
When the mailboxes live in your database, pass them to Mailbox::observe in the boot method of your
AppServiceProvider. Use a closure, so the database is only queried when the package needs the mailboxes. The
closure returns the same shape as the configuration:
Going Live
Run the subscribe command whenever you deploy. It creates, renews and removes Microsoft Graph subscriptions to match your configured mailboxes:
The package schedules this command hourly, and a delta sync every fifteen minutes, so make sure your
scheduler and a queue worker are running.
Microsoft must be able to reach your application over HTTPS at /webhooks/msgraph-mailbox.
At any time, you may check on your mailboxes. The command exits with a non-zero status when something needs your attention, so you can use it for monitoring, too:
Scheduling the Commands Yourself
If you'd rather decide when the commands run, turn off the automatic scheduling in your .env file:
Then schedule both commands in your application's routes/console.php file. Run the subscribe command at least once
a day so subscriptions are renewed before they expire, and the sync every few minutes, since it catches every change
a webhook missed and is your only source of events when webhooks are disabled:
If you only want different intervals, keep the automatic scheduling and change the subscriptions.cron and
sync.cron options in the config/msgraph-mailbox.php configuration file instead.
Registering the Webhook Route Yourself
The package registers its webhook route, POST /webhooks/msgraph-mailbox, outside the web middleware group, so
there is no session and no CSRF check. You may change the path and add middleware with the webhooks.path and
webhooks.middleware options in the config/msgraph-mailbox.php configuration file.
If the route should live on a specific domain or behind a prefix, turn off the automatic registration:
Then register the route in one of your route files with Mailbox::routes(). It still uses the configured path and
middleware, and the subscribe command picks up the resulting URL automatically:
Keep the route out of the web group, Microsoft's requests would fail the CSRF check, and don't rate limit it:
Microsoft retries rejected notifications and eventually drops subscriptions that keep failing. Disabling webhooks
entirely with MSGRAPH_MAILBOX_WEBHOOKS=false removes the route as well.
Receiving Messages
Every change in an observed folder becomes an event:
| Event | When it fires |
|---|---|
MessageReceived |
A message arrives in the folder, or is moved there. |
MessageMoved |
A message is moved to another folder of the mailbox. |
MessageDeleted |
A message is deleted and sits in Deleted Items. |
MessagePermanentlyDeleted |
A message is deleted permanently, or with Shift+Delete. |
MessageChanged |
A message is read, flagged, categorized or edited. Opt-in, see below. |
MessageMoved, MessageDeleted and MessagePermanentlyDeleted all implement MessageRemoved, so a single listener
can handle every way a message leaves a folder. To handle every event at once, listen for MessageEvent.
When a message is moved, you may ask where it went:
Each event carries the mailbox, the folder and the messageId. The message itself is loaded lazily, the first time
you call message():
MessageChanged is disabled by default. Outlook changes a message each time someone reads, flags or categorizes it,
so enable it only for the folders that really need it.
Events are delivered at least once. On rare occasions, such as a retried sync, a listener may see the same message
twice, so keep your listeners idempotent, for example by remembering the message's internetMessageId().
Working With Messages
You may work with any message of an observed mailbox through the Mailbox facade:
Reading Messages
The first property you access loads the message with a single request:
The body is fetched separately, as text unless you ask for HTML. Pass unique: true to get only the new part of a
reply, without the quoted conversation:
HTML bodies are returned as Microsoft delivers them, so sanitize them before you render them.
Automatic replies, bounces and your own sent mail can easily trigger loops. The package never skips a message on its own, but it helps you decide:
You may also get the raw RFC 822 message as a stream with $message->mime().
Attachments
Listing attachments only loads their metadata. Their content is downloaded when you ask for it:
safeFilename() strips paths and control characters from the sender's file name, and contents() returns the
content as a string. Attachments larger than attachments.max_bytes (25 MB by default) are never downloaded.
Organizing Messages
Actions may be chained, so handling a message usually reads like a sentence:
Here's everything you can do with a message:
Message ids stay the same when a message moves, so you may safely store them.
Queued Actions
Every action is also available as a queued job. Jobs are throttled per mailbox and unique for a few minutes, so dispatching the same action twice doesn't run it twice:
The jobs are MoveMessage, CopyMessage, MarkMessageRead, MarkMessageUnread, FlagMessage, CategorizeMessage,
DeleteMessage and PermanentlyDeleteMessage.
Microsoft allows about four concurrent requests per mailbox. When your own queued listeners or jobs call Graph, add the
ThrottleGraphRequests middleware. It shares the package's limit per mailbox and releases the job when Microsoft
throttles it or is unavailable:
A Complete Example
Let's attach replies to support tickets. Customers answer emails whose subject contains the ticket number, like
[TICKET-1042]. First, observe the support inbox:
Next, write a queued listener. It skips automatic replies, attaches the reply and its attachments to the ticket and archives the email:
firstOrCreate keyed by the internetMessageId keeps the listener idempotent. Finally, test it:
Testing
Mailbox::fake() swaps Microsoft Graph for an in-memory fake. The receive method adds a message and dispatches
MessageReceived through your real listeners, so you test them exactly as they run in production. Messages use the
shape of Microsoft Graph's message JSON, with attachments as contentBytes and the raw MIME message under mime:
You may also seed messages without dispatching an event with addMessage. Afterwards, assert what your code did:
Every assertion accepts the Message itself or its id, and an optional mailbox: argument. To test code that talks to the webhook route itself,
WebhookPayload::change($folder) and WebhookPayload::lifecycle($folder, LifecycleEvent::Missed) build notifications
with a valid client state.
How It Works
For every observed folder, the package keeps a Microsoft Graph subscription and a delta link. When something changes, Microsoft notifies the webhook route, which queues a delta sync of that folder. The notification itself is never trusted: the delta sync asks Microsoft what changed and compares it with the messages it already knows. A scheduled sync runs every fifteen minutes as a safety net, so a missed notification delays an event but never loses it.
The first sync of a folder records the messages that are already there without firing any events. From then on, every change becomes an event. Message ids are immutable, so an id stays valid after a message moves.
Local Development
Microsoft can't reach localhost, so locally you have two options. Disable the webhooks and let the delta sync deliver
your events:
Or share your site through a tunnel such as herd share or ngrok and point Microsoft to it:
Security
Mailbox::for()only acts on observed mailboxes and the patterns inallowed_mailboxes, so an address that comes from user input can never reach another mailbox of your tenant.Mailbox::forUnrestricted()skips this check; when you use it, authorizing the address is up to you.- Every subscription has its own random client state. Only its hash is stored, and notifications with an unknown subscription or a wrong client state are dropped without any request to Microsoft.
- The Graph client only ever sends its token to
https://graph.microsoft.com/v1.0/. - Events and queued jobs only carry ids. Message content never ends up in your queue or in
failed_jobs.
If you discover a security vulnerability, please email the maintainers instead of opening an issue.
Changelog
Please see the CHANGELOG for what has changed recently.
Credits
- Tim Geisendoerfer
- All Contributors
License
The MIT License (MIT). Please see the License File for more information.
All versions of laravel-msgraph-mailbox with dependencies
guzzlehttp/psr7 Version ^2.0
illuminate/contracts Version ^12.53|^13.0
innoge/laravel-msgraph-mail Version ^3.0
spatie/laravel-package-tools Version ^1.16