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

Symfony Mailer Bundle Laravel Package

tomazahlin/symfony-mailer-bundle

A Symfony bundle that integrates Symfony Mailer into your application, giving you configurable transports and mailer services for sending emails through a clean, framework-native setup.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wraps Laravel's mailer to expose header and envelope controls that core Mail doesn't surface cleanly. Release 2.2.1 is a patch that adds Return-Path header support, so bounces can be routed to a dedicated mailbox instead of your From address.

  1. Install and pin:
composer require <vendor>/<package>:^2.2
  1. Publish the config (if you haven't already) and clear caches:
php artisan vendor:publish --tag=<package>-config
php artisan config:clear
  1. Look first at, in order:

    • config/<package>.php — the return-path / envelope options added in 2.2.x
    • The package's service provider — to confirm the mailer decorator is registered for the mailers you actually use (smtp, ses, sendmail)
    • README / CHANGELOG for the 2.2.1 entry, which documents the exact key name
  2. First use case — route bounces away from your primary sender:

// config/<package>.php
'return_path' => env('MAIL_RETURN_PATH', '[email protected]'),
[email protected]

Send a test mailable and inspect the raw source at the receiving end: Return-Path: <[email protected]> should be present, and your From should be unchanged. That single check validates the whole feature.

Implementation Patterns

Global default, per-message override. Set the config default once, then override for specific mailables — transactional mail usually wants a different bounce mailbox than marketing mail:

public function build()
{
    return $this->subject('Your receipt')
        ->withSymfonyMessage(function (Email $message) {
            $message->getHeaders()->addMailboxHeader(
                'Return-Path',
                '[email protected]'
            );
        });
}

VERP / plus-addressing for attribution. Combine the header with a per-recipient address so bounces are traceable without parsing the DSN body:

$returnPath = "bounces+{$user->id}@example.com";

Then a single inbound mailbox (Postmark inbound, Mailgun routes, SES receipt rule) can map the local-part back to a user and suppress them automatically.

Pair it with an envelope sender. The header is what the receiving MTA records; the envelope sender (MAIL FROM) is what SPF/DMARC and most MTAs actually act on. If the package exposes both, set both to the same address, or your header will be silently rewritten. For sendmail transports this is the -f flag — check MAIL_SENDMAIL_COMMAND.

Queued mail. Because the header is applied at message build time, it survives serialization for queued mailables. Set it inside build() or via withSymfonyMessage(), not in the controller, so the queued job produces an identical message.

Testing. Assert the header rather than the rendered body:

Mail::fake();
Mail::to($user)->send(new Receipt($user));
Mail::assertSent(Receipt::class, function ($mail) use ($user) {
    return $mail->hasTo($user->email);
});

For a real header assertion, drop Mail::fake() and use the array or log transport, then inspect Mail::getSymfonyTransport()->messages() or the log file.

Gotchas and Tips

  • Return-Path ≠ Reply-To ≠ From ≠ Sender. Four different things. Return-Path is set by the receiving MTA and reflects the envelope sender; Reply-To is a human-facing hint. Setting only the header does nothing if your transport rewrites the envelope.
  • Providers may override it. Amazon SES stamps its own Return-Path unless you configure a custom MAIL FROM domain. Mailgun/Postmark may similarly normalize. Verify against a real send, not just the local log transport.
  • SPF/DMARC alignment. The Return-Path domain participates in SPF. If you point it at a domain you haven't authorised in DNS, you'll trade bounce routing for deliverability problems. Use a subdomain (bounces.example.com) with its own SPF record and MX.
  • Config caching bites. MAIL_RETURN_PATH changes won't take effect until php artisan config:clear (and a queue restart: php artisan queue:restart — workers hold the old config).
  • Debugging the raw message. Use the log mailer to see exactly what the package emits before your provider touches it:
MAIL_MAILER=log php artisan tinker

Then send a mailable and read storage/logs/laravel.log. Diff that against the headers of a mail received at a real inbox to spot provider rewriting.

  • Patch release, low risk — but pin it. 2.2.1 is additive, so no breaking changes are expected from 2.2.0. Still, pin ^2.2.1 and run your mail tests before deploying, since header ordering/duplication bugs in this area are easy to introduce and hard to notice.
  • Avoid duplicate headers. If you set both the config default and a per-message header, you may end up with two Return-Path headers in the raw output. Symfony's addMailboxHeader appends; use setHeader() semantics or make the per-message path the only one.
  • Extension point. If the package exposes a header resolver or an event before send, hook there rather than copying address logic across mailables — that's the cleanest place to implement bounce-address attribution globally.
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