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 Web Mailer Laravel Package

creagia/laravel-web-mailer

Preview and debug outgoing Laravel emails in a built-in web inbox. Laravel Web Mailer captures messages sent by your app so you can inspect recipients, headers, HTML/text content, and attachments without external mail tools.

View on GitHub
Deep Wiki
Context7

Getting Started

This package adds a web mail transport to Laravel so Mail/Notification messages are delivered by HTTP POST to an endpoint you control (or a provider that accepts mail over HTTP) instead of SMTP. It is the pragmatic choice when outbound port 25/465/587 is blocked — Lambda/Vapor, Cloud Run, some container platforms — or when mail is relayed through an internal API gateway or a Cloudflare Worker.

Minimal setup:

  1. composer require creagia/laravel-web-mailer:^2.0 — 2.0.0 requires Laravel 11–13 and PHP 8.2+ (8.5 supported). Laravel 9/10 users must stay on 1.0.x.
  2. Add a mailer to config/mail.php alongside your existing ones:
'mailers' => [
    'web' => [
        'transport' => 'web',
        // endpoint + auth keys — confirm exact names against the package config
    ],
],
  1. Set MAIL_MAILER=web and the endpoint/credentials in .env, then php artisan config:clear.
  2. Smoke-test: Mail::raw('hello', fn ($m) => $m->to('[email protected]')->subject('Test'));

First real use case: transactional mail (password resets, receipts) from a serverless deployment. Keep your existing SMTP/mailgun/log mailers configured — this package is a mailer, not a replacement for the mail system, so it can be adopted per-mailer rather than globally.

In 2.0 the transport registration was simplified, so the old Mail::extend('web', ...) call in a service provider is no longer part of the setup. Find the transport name in the package's service provider before wiring config.

Implementation Patterns

Named mailers, not a global swap. Define mailers.web, mailers.smtp, mailers.log, and select per-send with Mail::mailer('web')->send(...), ->mailer('web') on a Mailable, or $mailable->mailer = 'web'. This lets you route bulk mail through SMTP and transactional mail through the HTTP relay, and keeps local dev on log.

Keep Mailables transport-agnostic. Nothing about a Mailable or Notification changes — that is the main appeal. Existing ShouldQueue mailables start using the transport by switching the mailer, with no rewrite.

Queue everything. The transport makes a synchronous HTTP call inside the mail send; a slow endpoint directly delays the request. Implement ShouldQueue and set $tries/$backoff on the mailable or use the queue connection's retry settings.

Use the failover mailer for resilience:

'failover' => [
    'transport' => 'failover',
    'mailers' => ['web', 'smtp'],
],

This is often the best production configuration: HTTP first, SMTP as fallback (or the reverse), with retries handled by the queue.

Serverless integration. On Vapor/Lambda the HTTP transport avoids VPC/SMTP egress entirely. Point the endpoint at your relay, keep the payload small, and push sending to SQS via the queue so a slow relay does not eat into the Lambda timeout.

Multiple endpoints. Use two mailers (e.g. web_transactional, web_bulk) backed by separate config entries when different relays or credentials are needed per flow.

Testing. Combine Mail::fake() (assert the mailable was queued/sent) with Http::fake() (assert the POST actually goes out when you exercise the transport directly). Assert on the outbound payload — recipients, subject, and that the HTML body is present — since that payload is your integration contract with the endpoint.

Local development. Keep MAIL_MAILER=log (or Mailpit) locally and only enable web in staging/production; otherwise you need a reachable relay just to render a password reset.

Gotchas and Tips

  • 2.0.0 is a breaking major for framework support only. Dropping Laravel 9/10 is the only BC break flagged; the transport-registration change is internal. Still, run the test suite after upgrading and check that composer.json constraints resolve — a locked laravel/framework on 10.x will hard-fail the install.
  • Remove the old manual registration. If you previously called Mail::extend('web', ...) or registered a custom Transport in a service provider, delete it. Registering twice can shadow the package transport or throw on duplicate resolution, and the failure looks like an unrelated mail error.
  • config:cache bites. Changing .env values for the endpoint/token has no effect until you re-run config:cache. This is the single most common "the package stopped working" cause on deployed environments.
  • Attachments inflate. Base64 encoding adds ~33% to file size, and API gateways commonly cap request bodies at 6–10 MB. Large PDFs should be sent as a link, not an attachment, or split across a different mailer.
  • Set an explicit timeout and treat failures as transport errors. A hung relay will block a worker until the default connects. Give the HTTP client a short timeout, catch the transport exception, and let the queue retry with backoff. A non-2xx response should be surfaced, not swallowed — silently "sent" mail is worse than a failed job.
  • Debug with events and HTTP logging. MessageSending/MessageSent/MessageFailed events fire as usual, so an event listener logging the mailable class is your first diagnostic. For the wire, add a global HTTP client middleware (Http::globalRequestMiddleware) to log the outgoing request/response; do not log the auth header.
  • Watch remote rate limits. A relay or API gateway throttling at N requests/minute will produce 429s that look like random queue failures. Throttle the queue job (RateLimited middleware) rather than retrying blindly.
  • Auth and headers live in config, not code. Keep the token in .env per environment and confirm TLS verification is on; self-signed internal relays need an explicit opt-out, which should never ship enabled.
  • Charset and multipart quirks. HTML-only vs HTML+text, non-UTF-8 subjects, and inline images are the usual sources of "the mail arrives empty/garbled." Send a test with an attachment and a non-ASCII subject to every new endpoint before trusting it.
  • Verify what the endpoint expects. The package defines the JSON shape it POSTs; your relay must match it (field names for from/to/cc/bcc, body format, attachment encoding). Getting this wrong usually returns a 200 with the mail dropped — assert on a received message in staging, not just on a 2xx status.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin