PHPackages                             whilesmart/eloquent-outreach - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. whilesmart/eloquent-outreach

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

whilesmart/eloquent-outreach
============================

Host-agnostic user outreach for Laravel: compose messages with a call to action, target audiences, and track per-recipient deliveries across pluggable channels.

0280↓50%PHP

Since Jun 27Pushed 1mo agoCompare

[ Source](https://github.com/whilesmartphp/eloquent-outreach)[ Packagist](https://packagist.org/packages/whilesmart/eloquent-outreach)[ RSS](/packages/whilesmart-eloquent-outreach/feed)WikiDiscussions dev Synced 2w ago

READMEChangelogDependenciesVersions (2)Used By (0)

Whilesmart Eloquent Outreach
============================

[](#whilesmart-eloquent-outreach)

Host-agnostic user outreach for Laravel. Compose a message with a call to action, target an audience, and track a per-recipient delivery, all over channels your app implements. The package owns the workflow; your app owns how recipients are found, addressed, personalized, and sent.

Installation
------------

[](#installation)

```
composer require whilesmart/eloquent-outreach
php artisan vendor:publish --tag=outreach-migrations
php artisan migrate
```

Concepts
--------

[](#concepts)

- **Outreach** — one composed message: subject, body, CTA (`cta_label` + `cta_url`), `channel`, `audience` criteria, status, optional `scheduled_at`, and rolled-up `stats`. Optional polymorphic `owner` (sender) and `campaign` (a campaign "has many" outreaches).
- **Delivery** — one row per recipient, with status and timestamps. This is what later per-recipient actions (resend, view, mark) hang off.

What the host implements
------------------------

[](#what-the-host-implements)

```
use Whilesmart\Outreach\Contracts\AudienceResolver;  // criteria -> recipient models
use Whilesmart\Outreach\Contracts\MessageRenderer;   // outreach + recipient -> RenderedMessage
use Whilesmart\Outreach\Contracts\OutreachChannel;   // deliver a RenderedMessage
```

Bind your implementations in a service provider:

```
$this->app->bind(AudienceResolver::class, MyAudienceResolver::class);
$this->app->bind(OutreachChannel::class, MyEmailChannel::class);
// MessageRenderer defaults to attribute token replacement ({{first_name}});
// bind your own for richer templating.
```

Safe defaults ship out of the box: the audience resolves to nobody and the channel sends nowhere until you bind real ones.

Sending
-------

[](#sending)

```
use Whilesmart\Outreach\Models\Outreach;
use Whilesmart\Outreach\Services\OutreachDispatcher;

$outreach = Outreach::create([
    'channel' => 'email',
    'subject' => 'Hi {{first_name}}',
    'body' => 'We added something you will like.',
    'cta_label' => 'Open Trakli',
    'cta_url' => 'https://trakli.app/dashboard',
    'audience' => ['type' => 'inactive', 'days' => 30],
]);

app(OutreachDispatcher::class)->dispatch($outreach);
```

The dispatcher resolves the audience, creates a `Delivery` per recipient, renders and sends each through the bound channel, rolls the results onto the outreach, and emits `OutreachDispatched`, `DeliverySucceeded`, and `DeliveryFailed` for the host to bridge.

Campaigns
---------

[](#campaigns)

An outreach can belong to a campaign via the optional `campaign` morph, so a campaign (in your app or another package) can own many outreaches without this package depending on it.

License
-------

[](#license)

MIT. WhileSmart LTD.

###  Health Score

25

—

LowBetter than 35% of packages

Maintenance60

Regular maintenance activity

Popularity17

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/a1ca6f6e01ecbfe6640ff410c4f0321054fb48d05a5f843c2b89887b90369bcd?d=identicon)[whilesmart](/maintainers/whilesmart)

---

Top Contributors

[![nfebe](https://avatars.githubusercontent.com/u/14317775?v=4)](https://github.com/nfebe "nfebe (1 commits)")

### Embed Badge

![Health badge](/badges/whilesmart-eloquent-outreach/health.svg)

```
[![Health](https://phpackages.com/badges/whilesmart-eloquent-outreach/health.svg)](https://phpackages.com/packages/whilesmart-eloquent-outreach)
```

###  Alternatives

[inpsyde/wp-translation-downloader

Composer plugin to download translations from wordpress.org API.

51679.2k4](/packages/inpsyde-wp-translation-downloader)[stefangabos/zebra_pagination

A generic, Twitter Bootstrap compatible, PHP pagination library that automatically generates navigation links

11924.0k](/packages/stefangabos-zebra-pagination)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
