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 Mailjet Driver Laravel Package

thedoctor0/laravel-mailjet-driver

thedoctor0/laravel-mailjet-driver provides a Mailjet transport for Laravel's native mail system, letting you send email through Mailjet's API via the Mail facade. Configure credentials and use familiar Laravel mail workflows with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a mail transport for Laravel plus a thin wrapper around Mailjet's Send API. Use it when you want Mailjet as MAIL_MAILER for ordinary Laravel mailables, with the option to bypass the Mail facade for payloads it can't express.

  1. Check your constraints first — 2.1.x supports Laravel 11–13 on PHP 8.2+. On Laravel 9–10 you must stay on the 1.x line; treat the Laravel upgrade as a prerequisite, not an afterthought.

  2. Install and publish config:

    composer require thedoctor0/laravel-mailjet-driver:^2.1
    php artisan vendor:publish --tag=mailjet
    
  3. Put credentials in .env (MAILJET_APIKEY / MAILJET_APISECRET) and point Laravel at the transport:

    MAIL_MAILER=mailjet
    
  4. Smoke-test both paths immediately, because they fail differently:

    // 1) Standard Laravel mail path
    Mail::raw('ping', fn ($m) => $m->to('[email protected]')->subject('ping'));
    
    // 2) Direct Send API path (new in 2.1)
    $response = Mailjet::sendEmail([
        'From' => ['Email' => '[email protected]', 'Name' => 'App'],
        'To'   => [['Email' => '[email protected]']],
        'Subject' => 'ping',
        'TextPart' => 'ping',
    ]);
    

    Then dump $response->getData() — if it contains a Messages[0].Errors array, your credentials or sender are wrong even though nothing threw.

Where to look first: the published config/mailjet.php (key names and transport wiring), then the package's Mailjet entry point for sendEmail() / sendSms(). First real use case is almost always "send transactional mail through Mailjet templates" — a Mailable for simple notifications, sendEmail() with TemplateID + Variables for branded templates.

Implementation Patterns

Mailable-first for anything a human writes. The driver means Mail::to($user)->send(new WelcomeEmail($user)) works unchanged. Keep markdown/Blade mailables on this path — you get Laravel's testing helpers (Mail::fake()), localization, and queueing for free.

Reach for sendEmail() when the Mail facade is lossy. That covers:

  • Mailjet-hosted templates: TemplateID, TemplateLanguage => true, Variables.
  • Per-message behaviour the driver doesn't expose: SandboxMode, DeduplicateCampaign, CustomCampaign, TrackOpens, Headers.
  • Bulk/personalised fan-out where you want one call and the raw v3.1 Messages array, not N queue jobs.
  • Scheduled delivery (SentAt) — Mailjet queues it; don't hold a worker open.

Isolate the call in one place. Build a MailjetGateway/service class wrapping the facade, with sendTransactional(), sendTemplate(), sendSms(). Everything downstream depends on Mailjet's static API otherwise, and that makes it untestable and impossible to swap. Inject this service; keep the facade at the boundary.

Keep the v3.0 fallback behind a config flag. 2.1 defaults to the v3.1 payload shape and lets you request the v3 shape. Use the fallback only for payloads written before the upgrade (or a Mailjet endpoint that lags), and record why — v3.1 and v3.0 mix Recipients vs To/Cc, and a hybrid payload silently drops recipients instead of erroring.

Queue and retry at the job level. Send from queued jobs with $tries/backoff() rather than retrying inline. Mailjet returns HTTP 200 with per-message errors, so retries based on HTTP status alone will not fire — inspect the body, classify (invalid address = permanent, rate limit/throttle = retryable), and rethrow only the latter.

SMS lives beside mail, not through it. Mailjet::sendSms([...]) is a separate API (v4) with its own sender identity, credit, and country rules. Wrap it in its own small service, route OTP/alert traffic through it, and log the returned message ID — there's no delivery webhook here, so your own logs are the only trace.

Gotchas and Tips

  • 2.1 is a breaking platform jump. Laravel 11–13 / PHP 8.2+ only, and it pulls mailjet/mailjet-apiv3-php ^1.6 (needed for the public setAuthentication(), raw-data params, and PHP 8.4 fixes). If your app is on Laravel 10, composer require will resolve to 2.0.x or 1.x — read the resolved version, not the version you typed.
  • 200 OK ≠ sent. Always walk Messages[*].Errors / Status. A bad sender address, unverified domain, or malformed address returns a normal response with errors attached. A true-ish return from the facade means "HTTP was fine".
  • Re-run php artisan config:cache. After changing mail env vars in a deploy, cached config is the #1 cause of "it still uses the old key". Same for queue:restart — long-lived workers keep the old config and the old package version.
  • Mail::fake() doesn't cover the direct API. The driver path is fakeable; sendEmail()/sendSms() go through Guzzle inside mailjet-apiv3-php, so Http::fake() won't intercept them. Mock your gateway service (or bind a fake implementing the same interface) — don't reach for HTTP fakes and assume coverage.
  • Attachment and inline-image size. Base64 inflates payloads ~33%, and Mailjet caps total message size. Large PDFs should be a link, not an attachment; inline images belong in InlinedAttachments, not Attachments.
  • SMS specifics: phone numbers in E.164 (+44...), sender ID configured and in some countries pre-registered (US/Canada A2P), and messages segmented by length — cost scales with segments. Validate and normalise before calling, not after.
  • Rate limits are per-endpoint and per-key. Batch sensibly, back off on 429, and don't fan out hundreds of parallel Send API calls from one worker pool.
  • Extension point: the config file is the seam. Custom transport options, endpoint overrides, and the v3/v3.1 toggle belong there rather than hard-coded in your gateway class, so you can flip them per environment.
  • Upgrading: pin ^2.1, run the app test suite against the driver path and at least one direct sendEmail() integration test against Mailjet's sandbox mode — 2.1's 100% line coverage covers the package, not your payload shapes, which are exactly what changed between v3 and v3.1.
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.
frankkessler/guzzle-oauth2-middleware
delatbabel/site-config
delatbabel/applog
eusonlito/laravel-gettext
henzeb/housepedia-intelligence-laravel
aliqsm/laravel-authkit
itsjustvita/laravel-wp-migrator
uslanozan/laravel-cache-contract
adilazhari/laravel-trace
ulsyairil/ai-local-guardrails
dzwallet/laravel-sdk
glc36/maxloop-kernel
ikhbarnuridev/filament-mega-menu
mydnic/volet-chatbot
enadstack/laravel-localization
mydnic/volet-feature-board-filament-plugin
wmde/email-address
refinery29/test-util
dees040/laravel-api-responses
teamzac/geocoder