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

Mailgun Laravel Package

bogardo/mailgun

A Laravel package that integrates Mailgun into your app, providing a Mailgun transport driver for Laravel's Mailer plus a simple API wrapper for sending messages and managing mailing lists, routes, and webhooks.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Laravel wrapper around the official mailgun/mailgun-php v2 SDK that adds Blade rendering and a Mailgun facade. It is archived (last release October 2019), so treat it as maintenance-mode tooling for existing applications rather than a greenfield choice.

Minimal installation:

composer require bogardo/mailgun
  • Laravel 5.5+: auto-discovery registers Bogardo\Mailgun\MailgunServiceProvider and the Mailgun facade alias.
  • Laravel ≤5.4: add the provider to config/app.php and the alias 'Mailgun' => Bogardo\Mailgun\Facades\Mailgun::class.

Publish and configure:

php artisan vendor:publish --provider="Bogardo\Mailgun\MailgunServiceProvider"
MAILGUN_DOMAIN=mg.example.com
MAILGUN_SECRET=key-xxxxxxxxxxxxxxxxxxxxxxxx

config/mailgun.php holds domain, secret, endpoint (defaults to api.mailgun.net), a default from address/name, and views roots used by the view-rendering helpers.

First send:

use Mailgun;

Mailgun::send('emails.welcome', ['user' => $user], function ($message) use ($user) {
    $message->to($user->email, $user->name)
            ->subject('Welcome aboard')
            ->from('[email protected]', 'Example');
});

Where to look first, in order:

  1. The published config/mailgun.php — it tells you exactly which env keys and view roots are in play.
  2. The GitHub README on bogardo/mailgun — it has the full facade method list and the Message builder options.
  3. src/Bogardo/Mailgun/Mailgun.php and Message.php in vendor/ — the callback object is where tags, tracking, attachments, and recipient variables live.
  4. composer.lock — confirm which mailgun/mailgun-php major version resolved; it drives most compatibility issues.

The canonical first use case is transactional mail (welcome, password reset, receipts) where you already have Blade templates and want Mailgun's delivery/tracking without writing a transport.

Implementation Patterns

View-based sends. The views config lets you map logical names to directories so Mailgun::send('welcome', $data, $cb) renders resources/views/emails/html/welcome.blade.php (and a matching text variant if configured). This is the most common pattern — keep all mail bodies in Blade and pass a plain array of data.

HTML + text pairs. Configure both views.html and views.text; the package will render both parts for the same logical view name. If you only need plain text, use the raw/text helper instead of a view.

Attachments and inline images. Inside the callback:

$message->attach(storage_path('app/invoices/'.$invoice->id.'.pdf'), 'invoice.pdf');
$message->embed(storage_path('app/logo.png'));   // used as cid: reference in the HTML

Paths are filesystem paths, not URLs.

Message options. The callback object mirrors Mailgun's o: parameters — typically tag(), tracking(), dkim(), campaign(), and scheduled delivery. Reach for these before dropping to the raw SDK.

Batch sends with recipient variables. For newsletters or per-user personalization across many recipients, use the batch helper rather than looping the facade — one HTTP call instead of N, and Mailgun will substitute %recipient.first_name% tokens:

Mailgun::sendBatch('emails.newsletter', $recipients, function ($message, $recipient) {
    $message->to($recipient['email'])
            ->subject('Your weekly digest')
            ->recipientVariables(['first_name' => $recipient['first_name']]);
});

Check the README for the exact per-recipient argument shape in the version you have pinned.

Address validation. Use the facade's validation helper before persisting signups; it calls Mailgun's validation endpoint and saves you a round of bounces.

Wrap it, don't scatter it. Because this bypasses Laravel's Mail facade entirely, put calls behind a small App\Mail\MailgunSender service (or a queued Job) so tests and future migration to the built-in Mailgun transport touch one file. Dispatch an SendMailgunMessage job for anything user-triggered — facade calls are synchronous HTTP.

Testing. Mock the facade in feature tests:

Mailgun::shouldReceive('send')->once()->withArgs(fn ($view) => $view === 'emails.welcome');

Call Mailgun::clearResolvedInstances() in tearDown if the facade caches between tests. For unit tests, bind a fake implementation to Bogardo\Mailgun\Contracts\Mailgun.

Multi-domain / multi-tenant. The config is resolved once at boot, so runtime domain switching means config(['mailgun.domain' => $tenant->mailgun_domain]) before the call, or instantiating the underlying SDK directly for a cleaner separation.

Gotchas and Tips

  • It's archived — have an exit plan. Laravel 6+ ships a native Mailgun transport (MAIL_MAILER=mailgun + symfony/mailgun-mailer), and Laravel 9+ supports Mailgun via Symfony's bridge. New code should use that; this package is only justified if you depend on its Blade-view sugar or batch helpers.
  • SDK version pinning is the biggest trap. The package targets mailgun/mailgun-php v2. If Composer pulls v3/v4, the API surface changes (client construction, exceptions, method signatures) and you get fatals at runtime. Pin mailgun/mailgun-php:^2 in your root composer.json and verify after every composer update.
  • PHP 8 / Laravel 9+ compatibility is unverified. v2 of the SDK predates PHP 8 typing changes. Run the test suite on your target runtime before upgrading Laravel.
  • EU domains need the EU endpoint. Set 'endpoint' => 'api.eu.mailgun.net' for EU-region domains; the default US endpoint returns 401/404 for them. The secret is region-scoped.
  • API key prefix. Use exactly the key shown in the dashboard (key-…). Accidentally prefixing api: (or stripping it) is a classic 401 source; behavior differs between SDK patch versions.
  • Config caching. php artisan config:cache freezes mailgun.domain/secret. Keep env() calls only inside config/mailgun.php, never at call sites.
  • Sandbox domains only deliver to authorized recipients. If "mail silently disappears" in staging, check the domain's authorized-recipients list before debugging code.
  • No Mailable or Notification-channel support. You cannot pass this to Mail::to()->send(new Welcome). Either call the facade from inside the Mailable's build(), or implement a custom notification channel that delegates to your wrapper service.
  • Errors are SDK exceptions, not Laravel ones. Catch Mailgun\Exception\HttpClientException (400/401/404) and HttpServerException (5xx); log getResponseBody() — Mailgun's error JSON names the offending parameter.
  • Rate limits and size limits. 429/420 responses are throttling, not bugs; back off and retry. Individual messages cap at ~25 MB and 1,000 recipients; batches cap around 1,000 messages. Inline base64 images blow the size limit fast — use embed().
  • Attachment paths must exist and be readable at send time; the SDK throws, and this is easy to miss when files are generated asynchronously.
  • Facade alias collisions. If another Mailgun wrapper is installed, two Mailgun aliases fight over the root. Check config/app.php aliases and composer show | grep mailgun.
  • Blade data scope. The callback's $message is not available inside the view; everything the template needs must be in the data array you pass to send().
  • Extension point. Bind your own class to Bogardo\Mailgun\Contracts\Mailgun in a service provider to swap in a decorator (logging, dry-run mode, tenant routing) without touching call sites — the facade resolves through the container.
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