PHPackages                             joepages/laravel-emails - 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. joepages/laravel-emails

ActiveLibrary

joepages/laravel-emails
=======================

Polymorphic emails package for Laravel - Attach N emails to any model

v1.1.0(3mo ago)0328↓50%MITPHPPHP ^8.2CI passing

Since Feb 2Pushed 3mo agoCompare

[ Source](https://github.com/joepages/laravel-emails)[ Packagist](https://packagist.org/packages/joepages/laravel-emails)[ Docs](https://github.com/joepages/laravel-emails)[ RSS](/packages/joepages-laravel-emails/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (6)Versions (3)Used By (0)

Laravel Emails
==============

[](#laravel-emails)

[![Tests](https://github.com/joepages/laravel-emails/actions/workflows/tests.yml/badge.svg)](https://github.com/joepages/laravel-emails/actions/workflows/tests.yml)[![Latest Version on Packagist](https://camo.githubusercontent.com/08a3081ea8d003deefb37c5962b6198386a419deeb089b737c3c456488755411/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6a6f6570616765732f6c61726176656c2d656d61696c732e737667)](https://packagist.org/packages/joepages/laravel-emails)[![License](https://camo.githubusercontent.com/ff1733efa6d4f7922536c03c8762a1c57fda104670506573aeae753c38bb0d20/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6a6f6570616765732f6c61726176656c2d656d61696c732e737667)](https://packagist.org/packages/joepages/laravel-emails)

Polymorphic email addresses for Laravel. Attach multiple email addresses to any Eloquent model with full CRUD, bulk sync, primary management, verification tracking, and multi-tenancy awareness.

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11 or 12

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

[](#installation)

```
composer require joepages/laravel-emails
```

Run the install command to publish the config and migrations:

```
php artisan emails:install
php artisan migrate
```

The installer auto-detects [stancl/tenancy](https://tenancyforlaravel.com/) and publishes migrations to `database/migrations/tenant/` when present.

### Install options

[](#install-options)

```
php artisan emails:install --force            # Overwrite existing files
php artisan emails:install --skip-migrations  # Only publish config
```

Quick Start
-----------

[](#quick-start)

### 1. Add the trait to your model

[](#1-add-the-trait-to-your-model)

```
use Emails\Concerns\HasEmails;

class Facility extends Model
{
    use HasEmails;
}
```

### 2. Add the controller trait

[](#2-add-the-controller-trait)

```
use Emails\Concerns\ManagesEmails;

class FacilityController extends BaseApiController
{
    use ManagesEmails;
}
```

### 3. Register routes

[](#3-register-routes)

```
Route::emailRoutes('facilities', FacilityController::class);
```

This registers the following routes:

MethodURIActionGET`/facilities/{facility}/emails``listEmails`POST`/facilities/{facility}/emails``storeEmail`PUT`/facilities/{facility}/emails/{email}``updateEmail`DELETE`/facilities/{facility}/emails/{email}``deleteEmail`Model Trait API
---------------

[](#model-trait-api)

The `HasEmails` trait provides three relationships on your model:

```
$facility->emails;                    // All emails (MorphMany)
$facility->primaryEmail;              // Primary email (MorphOne)
$facility->emailsOfType('work');      // Filtered by type (MorphMany)
```

Email Model
-----------

[](#email-model)

### Fields

[](#fields)

FieldTypeDescription`type`stringEmail type (`personal`, `work`, `billing`, `other`)`is_primary`booleanWhether this is the primary email`email`stringThe email address`is_verified`booleanWhether the email has been verified`verified_at`datetime|nullWhen the email was verified`metadata`array|nullCustom JSON data### Scopes

[](#scopes)

```
Email::primary()->get();              // Only primary emails
Email::ofType('work')->get();         // Filter by type
Email::forModel($facility)->get();    // All emails for a specific model
Email::verified()->get();             // Only verified emails
```

### Helpers

[](#helpers)

```
$email->markAsPrimary();     // Sets as primary, unsets all others for the same parent
$email->markAsVerified();    // Sets is_verified=true and verified_at=now
$email->domain;              // "example.com" (domain part of the address)
```

Controller Trait
----------------

[](#controller-trait)

The `ManagesEmails` trait provides two integration modes:

### Standalone CRUD

[](#standalone-crud)

Use the `storeEmail`, `updateEmail`, `deleteEmail`, and `listEmails` methods directly via the route macro.

### Bulk Sync via BaseApiController

[](#bulk-sync-via-baseapicontroller)

When your controller extends `BaseApiController`, the `attachEmail()` method is called automatically during `store()` and `update()`. Send an `emails` array in the request body:

```
{
  "name": "Main Facility",
  "emails": [
    {
      "id": 1,
      "email": "updated@example.com"
    },
    {
      "email": "billing@example.com",
      "type": "billing",
      "is_primary": true
    }
  ]
}
```

- Records **with an `id`** are updated
- Records **without an `id`** are created
- Existing records **not included** in the array are deleted

API Resource
------------

[](#api-resource)

Add emails to your JSON responses:

```
use Emails\Concerns\WithEmailsResource;

class FacilityResource extends JsonResource
{
    use WithEmailsResource;

    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            ...$this->emailsResource(),
        ];
    }
}
```

Validation
----------

[](#validation)

The `EmailRequest` form request validates:

FieldRules`email`required, email, max:255`type`sometimes, string (validated against config when `allow_custom_types` is false)`is_primary`sometimes, boolean`is_verified`sometimes, boolean`verified_at`nullable, date`metadata`nullable, arrayConfiguration
-------------

[](#configuration)

```
// config/emails.php

return [
    // 'auto' detects stancl/tenancy, 'single' or 'multi' to force
    'tenancy_mode' => 'auto',

    // Allowed email types
    'types' => ['personal', 'work', 'billing', 'other'],

    // Default type when none specified
    'default_type' => 'personal',

    // When false, only types in the 'types' array are accepted
    'allow_custom_types' => true,
];
```

Database Schema
---------------

[](#database-schema)

```
CREATE TABLE emails (
    id              BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
    emailable_type  VARCHAR(255) NOT NULL,
    emailable_id    BIGINT UNSIGNED NOT NULL,
    type            VARCHAR(50) DEFAULT 'personal',
    is_primary      BOOLEAN DEFAULT FALSE,
    email           VARCHAR(255) NOT NULL,
    is_verified     BOOLEAN DEFAULT FALSE,
    verified_at     TIMESTAMP NULL,
    metadata        JSON NULL,
    created_at      TIMESTAMP NULL,
    updated_at      TIMESTAMP NULL,

    INDEX (emailable_type, emailable_id),
    INDEX (type),
    INDEX (is_primary),
    INDEX (email)
);
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance80

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

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.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

106d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/8759bf04f295d7d6dcaf23c6defdaee79de5fb85d7a4fbd3fe4e38a885bc7134?d=identicon)[joepages](/maintainers/joepages)

---

Tags

laravelmulti-tenancyemailspolymorphic

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/joepages-laravel-emails/health.svg)

```
[![Health](https://phpackages.com/badges/joepages-laravel-emails/health.svg)](https://phpackages.com/packages/joepages-laravel-emails)
```

###  Alternatives

[spatie/laravel-health

Monitor the health of a Laravel application

86910.0M83](/packages/spatie-laravel-health)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)[yadahan/laravel-authentication-log

Laravel Authentication Log provides authentication logger and notification for Laravel.

416632.8k5](/packages/yadahan-laravel-authentication-log)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)

PHPackages © 2026

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