Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Mail Export Laravel Package

pod-point/laravel-mail-export

A Laravel package from Pod Point for exporting your mailables, letting you capture rendered emails without sending them. Handy for inspecting templates, archiving output, and debugging mail in development, with a simple setup that fits your existing mail config.

View on GitHub
Deep Wiki
Context7

Getting Started

Install (2.2.0 constraints):

composer require pod-point/laravel-mail-export:^2.2

2.2.0 supports Laravel 9, 10, and 11 on PHP 8.1+. If you pinned to 2.1.0 because a prior release dropped PHP 8.1, 2.2.0 lifts that pin — this release re-introduces 8.1 support for the Laravel 9/10 line while adding the L11 branch. That combination is the main reason to bump.

Where to look first:

  1. vendor/pod-point/laravel-mail-export/README.md — the package is deliberately small; the README is the documentation.
  2. vendor/pod-point/laravel-mail-export/config/ — the publishable config is where disk, path, and filename behaviour live.
  3. composer.json of the package — confirm the exact illuminate/* and php constraints before adding to a legacy app, since L11 support landed as a separate matrix entry.
php artisan vendor:publish --tag=mail-export-config   # verify tag name in README

First use case — stop needing a fake SMTP sink. Rather than wiring Mailtrap/Mailpit just to eyeball a transactional email, render the mailable and dump it to disk:

// routes/web.php, local env only
Route::get('/_mail/{mailable}', function (string $mailable) {
    $instance = app("App\\Mail\\{$mailable}");   // or resolve with fixtures
    return $instance->export();                   // see README for exact API
});

That single route replaces most of the "send a test email to myself" loop and gives you a file you can open in a mail client or diff in git.

Implementation Patterns

1. On-demand export from Tinker / a route. Constructor-inject real or factory-built models, call the export method, open the resulting file. Best for one-off visual checks on a single template.

2. Trait on the Mailable. Applying the package trait to your base Mailable (or a App\Mail\BaseMailable you already have) makes every mailable exportable for free. This is the highest-leverage integration: one use in one class, and every subclass inherits it.

namespace App\Mail;

use Illuminate\Mail\Mailable;
use PodPoint\MailExport\Concerns\Exportable; // confirm namespace

abstract class BaseMailable extends Mailable
{
    use Exportable;
}

3. Local-only global hook. A LocalServiceProvider that exports every outgoing mail in local/testing gives you a complete, chronological corpus of what your app actually sends — far more representative than hand-picked fixtures:

// AppServiceProvider::boot()
if ($this->app->environment('local')) {
    // e.g. listen on MessageSending / MessageSent and export the mailable
}

Keep this strictly out of production; see the PII note below.

4. Test assertions without sending. Construct the mailable, export it, and assert on the generated file. This is more robust than Mail::fake() + assertSeeInHtml() when you care about the rendered artefact (plain-text part, headers, inline images) rather than just the fact that a mailable was queued. Snapshot the exported file in CI and diff on PRs — template regressions become reviewable diffs instead of "looks fine to me".

5. CI artefact archival. In a pipeline, export your golden-path mailables and upload the output directory as a build artefact. Reviewers get a downloadable .eml per email without ever running the branch.

6. Per-mail overrides. Where the package exposes filename/disk configuration, override per mailable (e.g. invoice-{order_id}.eml) so exports are self-describing and stable across runs — stable filenames are what make the git-diff workflow viable.

Gotchas and Tips

  • Upgrading from 2.1.0: the two changes are additive (L11 matrix entry) and a revert (PHP 8.1 restored). No breaking API changes are announced — but "revert" commits are worth a quick skim of the diff if you built anything around the 2.1.0 constraint set. If you carry a conflict rule or a CI matrix that excludes 8.1, remove it, or you'll silently stay on 2.1.0.

  • Laravel 11's slimmer skeleton: L11 removed a lot of default config files. If you publish the package config, make sure nothing in your AppServiceProvider assumes a config/mail-export.php that wasn't published. Prefer reading config with defaults (config('mail-export.disk', 'local')).

  • PII in exported files — the big one. An exported email is a complete, unredacted message: recipient address, body, invoice lines, sometimes reset tokens. Never point the export disk at anything public, never commit exports, and add the export path to .gitignore before the first git add .. If you snapshot-export in CI, redact fixtures rather than real data.

  • Queued mailables don't render at dispatch time. If your mailables are ShouldQueue, exporting from the dispatch site may hand you a mailable with unresolved dependencies. Export inside build()/after the mailable is fully hydrated, or construct it directly with test data.

  • Attachments and inline images inflate exports fast. A single exported mail with an embedded logo can be hundreds of KB. Cap what you export, and consider a dedicated mail-export disk rather than sharing storage/app/public.

  • Data-heavy mailables need fixtures. Anything whose build() touches relations ($order->lines, $user->subscription) will throw on export if constructed empty. Use factories with explicit relationships rather than new InvoiceMail(order: Order::factory()->create()) — lazy-loaded relations are the usual failure point.

  • Filename collisions. Running an export loop on a schedule will silently overwrite unless the filename includes a timestamp, ID, or UUID. Check the package's default naming before wiring it into anything automated.

  • Rendering vs. sending divergence. Exported output comes from the Mailable render pipeline, not the mail transport. It won't catch transport-level issues (SPF/DKIM, bounce handling, provider templating) — don't treat a clean export as proof the email delivers.

  • Debugging path: if exports land nowhere obvious, check (a) the configured disk's root, (b) storage/app permissions, and (c) whether a local-env guard is silently skipping the call. Log the absolute path on export rather than guessing.

  • Extension points to prefer: config-level disk/path overrides and subclassing your BaseMailable will survive minor upgrades far better than touching package internals. Given the package's small surface area, avoid reaching into vendor/ — a one-class wrapper in your own App\Mail namespace is cheap insurance.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo