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

Swiftmailer Bundle Laravel Package

kunstmaan/swiftmailer-bundle

Legacy Symfony bundle that integrates the Swiftmailer mailer library. Largely obsolete now that Swiftmailer is abandoned and Symfony Mailer is the standard, so it suits only older projects still relying on Swiftmailer.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. kunstmaan/swiftmailer-bundle is a Symfony bundle — it wires a Swiftmailer-based Mailer service into the container, with optional Doctrine-backed, multilingual email templates. You cannot composer require it into a Laravel app and get anything useful: it registers a Bundle, reads a kunstmaan_swiftmailer config tree, and expects Symfony's MailerInterface. The repository is archived, has 0 stars, and the last release (v3.6.0) is a single-commit constraint widening. Treat it as something you maintain or migrate away from in a legacy Kunstmaan CMS codebase, or as a pattern reference for how to build DB-driven templated mail in Laravel.

What v3.6.0 actually changed. One thing: composer.json now allows Symfony 6 packages ("Allow symfony 6 packages"). There are no new features, no API changes, no deprecations. It does not change the transport story — Swiftmailer itself is still EOL and unmaintained; the bundle only stops blocking composer update on a Symfony 6 host. Read it as "the fork maintainer unblocked a constraint", not "the package is alive again". The archived flag and the absence of security maintenance are unchanged, and there is exactly one contributor on this release.

Minimal steps in a legacy Symfony app:

  1. composer require kunstmaan/swiftmailer-bundle — pin the version to match your Symfony line: <3.6 for Symfony 4.x/5.x, ^3.6 only if you're on Symfony 6. Check composer.json require in the repo before installing; the tag boundaries are the whole story of this release.
  2. Verify the resolved swiftmailer/swiftmailer and symfony/* versions together with composer why-not. If you're on Symfony 6, this bundle being installable does not mean the rest of your mail stack is healthy — check that nothing else still drags in symfony/swiftmailer-bundle.
  3. Register the bundle: config/bundles.php under Symfony Flex, or app/AppKernel.php on the older skeleton.
  4. Import its service config if not auto-loaded, and configure the mailer/transport under swiftmailer: plus the bundle key (typically kunstmaan_swiftmailer:) in config/packages/*.yaml.
  5. If you want DB-stored templates, map the bundle's EmailTemplate entity into Doctrine and generate a migration — the table must exist before the mailer can render anything.
  6. Send a test through a Symfony console command or a controller, not through a queue, until you trust it.

Where to look first, in this order:

  • README.md — usually thin; skim it only for the config key names.
  • DependencyInjection/Configuration.php — the authoritative list of config options and the template_entity class parameter.
  • Mailer/ (the Mailer service and its interface) — this is the one class you'll actually call.
  • Entity/EmailTemplate.php (+ repository) — schema, locale columns, subject/body fields.
  • Resources/config/services.yml — service IDs you'll inject or decorate.
  • Resources/views/ — the Twig layout the body is rendered into.

First use case to validate the install: send a single localized welcome email where subject and body come from the database, rendered with Twig and a small array of variables. If that works end-to-end (including the correct locale fallback) — and the profiler shows the message — everything else is repetition. Do this on the exact Symfony/PHP pair you intend to ship on, because the v3.6.0 constraint bump is precisely the kind of change that shifts your minimum PHP.

Implementation Patterns

Core call pattern. Inject the bundle's mailer service rather than Symfony's raw mailer — the former is what knows about template entities and Twig rendering:

use Kunstmaan\SwiftmailerBundle\Mailer\Mailer; // confirm FQCN in the repo

public function __construct(private Mailer $mailer) {}

public function notify(User $user): void
{
    $template = $this->emailTemplates->findOneBySlug('welcome', $user->getLocale());

    $this->mailer->send(
        $template,
        $user->getEmail(),
        ['user' => $user, 'activationUrl' => $url] // Twig context
    );
}

Always pass a scalar or DTO-ish context. Passing full Doctrine entities into Twig invites lazy-loading inside the mail send path, which blows up when you move sending to a spool/queue consumer with a closed EntityManager.

Locale as a first-class concern. The whole reason to use this bundle over plain Swiftmailer is multilingual DB templates. Establish a lookup chain explicitly in your own wrapper service (requested locale → site default → hardcoded fallback), don't rely on the bundle to guess. Keep template slugs stable and treat translations as data, not code.

Spool instead of sending inline. Configure swiftmailer.spool (file or memory) and run swiftmailer:spool:send from cron/worker. This is the direct analogue of Laravel's queue driver:

Symfony/Swiftmailer Laravel equivalent
swiftmailer.spool: { type: file } + cron spool:send QUEUE_CONNECTION + php artisan queue:work
Mailer::send() inline Mail::to()->send() inline
spool + console consumer Mail::to()->queue(new Mailable)
EmailTemplate entity (DB, per-locale) email_templates table + Blade::render() inside a Mailable
Twig template for subject + body Blade view + Markdown mailable
swiftmailer:email:send dev command Mail::fake() + php artisan tinker

Laravel-side pattern if you're porting. Don't emulate the bundle's DB templates with eval or string-rendered PHP — render Blade strings from the DB row inside a Mailable:

public function build(): self
{
    $tpl = EmailTemplate::for('welcome', $this->locale);

    return $this->subject($tpl->subject)
        ->view('mail.layout')          // static shell, versioned in git
        ->with(['body' => Blade::render($tpl->body, $this->data)]);
}

Keep the layout in code and the content in the DB — that's the one design decision worth carrying over from this bundle.

Integration tipping points.

  • Put a thin domain service (NotificationMailer) in front of the bundle mailer. Every call site then goes through one place you can later repoint at symfony/mailer or a Laravel HTTP mail service.
  • If emails are triggered by Kunstmaan form/page-part submissions, hook at the form handler, not in a Twig template.
  • Test with Symfony's profiler mail panel and Mail::fake() equivalents; assert on rendered subject/body, not on the transport.
  • When you bump to the v3.6.0 tag, treat it as a dependency-graph event, not a feature upgrade: rebuild the container, re-run the mail smoke test, and diff composer.lock for transitive symfony/* jumps you didn't intend.

Gotchas and Tips

  • End-of-life is the headline. Swiftmailer was abandoned in favour of symfony/mailer (Nov 2021 deprecation, Nov 2022 EOL), and this bundle went archived right at that boundary. v3.6.0 loosening the Symfony constraint does not revive the transport — Swiftmailer the library is still dead code. There will be no security fixes. Any new work should target symfony/mailer (Symfony) or Laravel's built-in Mail/Mailable. Budget the migration rather than extending this.
  • v3.6.0 is a constraint bump, and constraint bumps are load-bearing. Symfony 6 support is a claim about installability, not about tested behaviour — a single PR from a single contributor with no accompanying test or CI signal in the notes. If you take it, pin ^3.6.0 exactly, run your own send/spool/profiler smoke test, and be aware that the "supports Symfony 6" line is unverified by the release itself.
  • Zero stars / zero dependents is a signal, not a stat. Pin the exact commit or tag in composer.json, and consider vendoring or forking if you must live with it — Packagist metadata for abandoned packages drifts, and tags like v3.6.0 can appear without the repo being meaningfully maintained.
  • Bundle registration is version-sensitive. Symfony Flex auto-registers; older skeletons need AppKernel::registerBundles(). A "service not found" error is almost always a registration or config-import problem, not a bug in the mailer.
  • Doctrine schema must be migrated. The EmailTemplate entity won't exist in your DB until you run a diff/migration. The mailer will throw a "table not found" or return no template — and depending on the code path, may silently send nothing. Check Entity/ for the exact table name.
  • Twig rendering of the subject is a trap. Variables in subjects skip HTML escaping expectations, and missing variables under strict_variables: true throw at send time. Validate template variables at save time in your admin UI, not at send time.
  • Spool failures are silent. memory spool only flushes at kernel terminate — a fatal error loses the mail. file spool needs write permissions on var/spool and a running spool:send job; if cron is missing, mail simply never leaves. Check the spool directory and the command's exit code before blaming the transport.
  • Debugging levers: the Symfony profiler's mail panel (dev only), the message-logger plugin (writes to logs when kernel.debug is on), and swiftmailer:email:send for a transport smoke test. If the profiler shows the message but the inbox is empty, it's transport/DNS/spam — not the bundle.
  • Extension points worth knowing: override the template class via the bundle's config key, decorate the mailer service (decorates: kunstmaan_swiftmailer.mailer) to add logging or a forced BCC in staging, and override Twig under templates/bundles/<BundleName>/. These three cover 90% of real customisation without forking.
  • Never send real mail from staging. Wire a Swiftmailer plugin (or a decorated mailer) that rewrites all recipients to a sink address and tags the subject with the original — the equivalent of Laravel's Mail::alwaysTo().
  • Serialization hazard with spooling. If your spool captures messages containing entities or closures in the Twig context, the consumer can fail on unserialize. Flatten all template variables to scalars/arrays before calling send().
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource