yieldstudio/symfony-spot-hit-notifier
A Symfony Notifier transport for Spot-Hit, letting you send notifications through Spot-Hit using Symfony’s Notifier component. Configure it via DSN and add Spot-Hit messaging to your Symfony app.
This package provides a custom Laravel mail transport. The 0.0.2 release clarified that the transport host value must be a bare hostname — do not include the https:// scheme in the host config.
Start here:
Install the transport:
composer require <vendor>/<package>
Publish its config (if the package exposes one):
php artisan vendor:publish --tag=<package>-config
Configure a mailer in config/mail.php:
'mailers' => [
'custom' => [
'transport' => 'custom', // matches the transport key registered by the package
'host' => env('CUSTOM_MAIL_HOST'), // bare host, e.g. smtp.example.com
'port' => env('CUSTOM_MAIL_PORT', 587),
'username' => env('CUSTOM_MAIL_USERNAME'),
'password' => env('CUSTOM_MAIL_PASSWORD'),
'encryption' => env('CUSTOM_MAIL_ENCRYPTION', 'tls'),
],
],
Point your default mailer at it:
MAIL_MAILER=custom
CUSTOM_MAIL_HOST=smtp.example.com
CUSTOM_MAIL_PORT=587
First use case: send a test message with php artisan tinker and Mail::raw('hello', fn ($m) => $m->to('[email protected]')->subject('test'));. If this succeeds, the transport is wired correctly.
Dedicated mailer, not global default. Register the transport as its own mailer so you can route specific notifications through it while leaving transactional mail on your existing mailer:
Notification::route('mail', '[email protected]')
->notify(new CriticalAlert(...));
Or select the mailer explicitly:
Mail::mailer('custom')->to($user)->send(new WelcomeMail($user));
Per-environment config. Keep host/credentials in .env and resolve the scheme via the separate encryption/scheme option rather than baking it into the host:
CUSTOM_MAIL_HOST=mail.internal.example.com
CUSTOM_MAIL_ENCRYPTION=tls
Multi-tenant / dynamic credentials. If hosts vary per tenant, build the mailer at runtime rather than mutating config/mail.php:
config(['mail.mailers.tenant' => [
'transport' => 'custom',
'host' => $tenant->mail_host, // ensure this is stripped of any scheme
// ...
]]);
Mail::mailer('tenant')->to($user)->send(new InvoiceMail($invoice));
Queued sending. Wrap outbound mail in queued Mailable/Notification classes so a slow or misconfigured remote host does not block the request cycle. This also gives you retries for free.
Testing. Use Mail::fake() for behavioural tests, and reserve a real send for a single integration/smoke test against a sandbox account. Assert on the mailable, not the transport.
The 0.0.2 host rule. The transport host must not contain https (or any scheme). Passing https://smtp.example.com will produce confusing connection failures. Store the bare hostname and let the package/encryption option handle the scheme. This is the single most likely source of "it works in staging but not prod" bugs, since env values copied from a dashboard URL often include the scheme.
Sanitise defensively when host values come from user input or a config UI:
$host = preg_replace('#^https?://#i', '', trim($rawHost));
$host = rtrim($host, '/');
Symptom-to-cause cheat sheet.
Connection refused / DNS error → host contains a scheme or trailing slash.encryption setting; use one source of truth for TLS.535 Authentication failed → credentials, not host; check username/password are actually reaching the transport config.Debugging. Enable verbose mail logging in a non-production environment and inspect the underlying SMTP/HTTP conversation:
// config/mail.php / logging config
'logging' => env('MAIL_LOGGING', true),
For deeper tracing, php artisan mail:send style test commands or a throwaway route that calls Mail::raw(...) inside a try/catch and dumps the exception is faster than reading stack traces from queued jobs.
Config caching. php artisan config:cache will happily freeze a bad host value. After changing mail config, always re-run php artisan config:clear (or config:cache again) — this is the most common reason a corrected .env appears to have no effect.
Extension points. The transport is a thin wrapper around an underlying client. If you need custom headers, timeouts, or proxy settings, look for a service provider binding or a Transport factory you can override in your own AppServiceProvider rather than editing vendor files. Prefer subclassing the provided transport and re-binding it in the container.
Pin and track. 0.0.x is pre-1.0: expect config-shape changes. Pin an exact version in composer.json, read the changelog on every bump, and keep a smoke test in CI so a host-format regression fails loudly rather than silently dropping mail.
How can I help you explore Laravel packages today?