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

Mail Php Laravel Package

wisedata/mail-php

wisedata/mail-php is a PHP mail package for Laravel and general PHP applications, offering a simple API for composing and sending email. It aims to make mail configuration and integration straightforward for projects that need dependable message delivery, with a clean developer experience.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a framework-agnostic PHP SDK for the WiseData Mail HTTP API (contacts + transactional email), not a Laravel package. There is no service provider, no auto-discovery, no config file to publish. Treat it like adding Stripe or an AWS SDK: you wire it up yourself.

  1. Install and pin:
composer require wisedata/mail-php
  1. Look here first, in this order:

    • README.md — likely short and possibly in Portuguese; skim for the constructor signature.
    • src/ — find the main client class and its constructor. You need to know: does it take an API key, a base URL, and an optional PSR-18/Guzzle client?
    • composer.json — confirm the PHP version constraint and whether Guzzle is a hard dependency. This determines your testing strategy.
  2. Pull credentials from the WiseData dashboard and put them in config/services.php, not in a vendor config file:

// config/services.php
'wisedata_mail' => [
    'key'  => env('WISEDATA_MAIL_KEY'),
    'url'  => env('WISEDATA_MAIL_URL', 'https://api.wisedata.com.br'),
],
  1. Bind it once in AppServiceProvider::register():
$this->app->singleton(\WiseData\Mail\Client::class, fn () => new \WiseData\Mail\Client(
    config('services.wisedata_mail.key'),
    config('services.wisedata_mail.url'),
));
  1. First use case: prove the credentials work with a single transactional send from php artisan tinker — not from a controller, not from a queued job. One call, one email in your inbox, then stop and read the response object shape before building anything else.

Implementation Patterns

Wrap it, don't sprinkle it. The vendor namespace should appear in exactly one or two files. Create App\Services\Mail\WiseDataMailer that exposes intent-revealing methods (sendReceipt, syncContact) and returns your own small result object. This is your insurance policy against the package being abandoned — swapping to raw Http:: calls later becomes a two-hour job instead of a refactor.

Transactional sends belong in jobs. The SDK has no queue awareness, no retry policy, and no backoff. Put every send inside a queued job with $tries, $backoff, and failed() handling. If the API supports an idempotency key, pass a deterministic one (e.g. order-{id}-receipt) so retries don't double-send; if it doesn't, dedupe with a sent_at column before dispatching.

Contact sync via model events, not controllers. Hook User::created / updated → SyncContactToWiseData job. Use updated sparingly — a naive listener will fire an API call on every last_seen_at touch. Guard with $user->wasChanged(['name','email','marketing_opt_in']).

Backfill with a chunked Artisan command. The contacts API will rate-limit you on a 10k-user import. User::chunkById(200, ...) with a usleep() or RateLimited job middleware beats a single loop that dies at record 400.

Dual-driver is normal. Most teams keep Laravel's native Mail for ops/internal mail (password resets, error alerts) and use WiseData only for product transactional mail where deliverability analytics matter. Don't try to force the SDK into a custom Mail transport unless you genuinely need Mail::to()->send() ergonomics — it's a lot of work for little gain.

Testing: bind a fake into the container in TestCase::setUp() and assert on your wrapper's calls, not the vendor client. If you need to test the client itself, check whether it accepts an injected Guzzle client — if it does, use MockHandler. If it constructs new GuzzleHttp\Client() internally, you can't intercept it and you should test only at the wrapper boundary.

Gotchas and Tips

  • Budget half a day for integration plumbing. No service provider, no facade, no config publish, no Mail:: integration, no queue hooks. The package gives you an HTTP client and nothing more. That's fine — just don't assume Laravel conventions exist.
  • Verify the actual class/method names against src/. With zero stars and zero dependents there's no Stack Overflow corpus. The README is the only doc; if method signatures don't match it, trust the code.
  • Exception handling is on you. Find the package's exception type (if it has one) and catch that specifically. A bare catch (\Exception $e) around a send will silently swallow a malformed-API-key error that should have paged you.
  • Set explicit timeouts. If the client builds its own Guzzle instance, the default connect timeout can hang a queue worker. If you can inject a client, pass ['timeout' => 10, 'connect_timeout' => 5].
  • Never log the client object or full request bodies. API keys travel in headers, and the contacts API payloads are personal data — dumping them into laravel.log is a LGPD/GDPR problem. Log the contact ID and status code only.
  • Pin the exact version and commit the lockfile. Single maintainer, no dependents, sparse release history — the blast radius of a bad ^1.0 bump is entirely yours. Check that the tag actually resolves on Packagist before assuming the advertised release exists.
  • Webhooks, if the API emits them, are unsigned until proven otherwise. Verify with a shared secret in the header yourself; don't assume the SDK handles it.
  • Watch for array-vs-object responses. Thin SDKs often json_decode($body, true) and hand back arrays, which means no IDE completion on the response. Wrap the response in a typed DTO in your service class so the rest of your app isn't doing $response['data']['id'] ?? null guesswork.
  • Rate limits are undocumented until you hit them. Centralize retry/backoff in the job middleware now rather than discovering it during a marketing campaign 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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core