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 Resend Laravel Package

jeffersongoncalves/laravel-resend

A Laravel integration for Resend, the transactional email API. Send mail through Resend using Laravel’s mailer, configure your API key, and access a simple service wrapper for Resend endpoints. A lightweight way to add Resend email delivery to Laravel apps.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the initial 1.0.0 release, so treat it as the first stable baseline rather than an upgrade — there is no migration path to worry about, but equally no battle-tested history to lean on. Pin it explicitly ("jeffersongoncalves/laravel-resend": "^1.0") and read the changelog link in the release notes alongside the README before adopting.

Where to look first, in order:

  1. config/resend.php after publishing — this is where the API key, default from address, and any transport/sandbox settings live. Almost every "why isn't it working" question resolves here.
  2. The service provider's register()/boot() — confirms whether the package registers a mail transport (so Mail::to(...)->send(...) routes through Resend) and/or binds a facade for the raw Resend API.
  3. The facade / client class — this is your entry point for anything beyond plain mail: domains, audiences, contacts, broadcasts, API keys.
  4. composer.json requirements — check the Laravel and PHP version constraints before assuming it drops into an older app.

Typical first use case — swap the mailer, keep your existing Mailables:

MAIL_MAILER=resend
RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
[email protected]
MAIL_FROM_NAME="Your App"
php artisan vendor:publish --tag=resend-config
php artisan config:clear   # config caching will bite you otherwise

Mail::to($user)->send(new WelcomeEmail($user));

If that works, the transport is wired. Then verify the raw-API path (e.g. sending a non-Mailable payload or listing domains) so you know both surfaces are live.

Implementation Patterns

Transport-first (recommended default). Keep using Laravel's Mail facade and Mailables. You inherit queues, ShouldQueue, markdown templates, attachments, and events (MessageSending/MessageSent) with zero changes. Resend becomes an infrastructure detail. This is the pattern to reach for 90% of the time.

Per-mailer configuration. Rather than overriding the global mailer, define a dedicated mailer in config/mail.php so you can run Resend alongside SMTP or SES:

'mailers' => [
    'resend' => [
        'transport' => 'resend',
    ],
    // ...
],

Then opt in per-send: Mail::mailer('resend')->to($user)->send(...). Useful for staged rollouts or sending transactional mail through Resend while bulk mail stays elsewhere.

Facade / client for resource operations. Use the package facade for things Laravel's mail layer has no concept of — creating domains, verifying DNS, managing audiences and contacts, retrieving delivery status. Wrap these in your own small service class rather than calling the facade from controllers; it keeps the vendor surface isolated and makes swapping providers a one-file change.

Queue everything. Resend is an HTTP API, so a slow or failing call is a network round-trip inside your request. Implement ShouldQueue on Mailables, or dispatch via a job. Pair with ->afterCommit() on the send if you're sending from inside a DB transaction — you don't want a confirmation email for a record that gets rolled back.

Testing integration. For unit tests, Mail::fake() works unchanged — assert on Mail::assertSent(WelcomeEmail::class) and never hit the API. Only the facade/resource calls need stubbing (typically Http::fake() against Resend's host, or a bound fake of the client interface if the package exposes one). Keep a .env.testing with a dummy RESEND_API_KEY so config validation doesn't throw at boot.

Webhooks (if present in this release). Register the route behind api middleware without CSRF, verify the signing secret from the Resend dashboard, and be idempotent — delivery events repeat.

Gotchas and Tips

  • Config cache. After changing config/resend.php or MAIL_MAILER in production, always php artisan config:clear (or re-run config:cache). This is the single most common cause of "it still uses the old key."
  • .env key naming. This package will use either RESEND_API_KEY or a package-prefixed key like RESEND_RESEND_API_KEY. Check the published config file's env() calls rather than assuming — a silently-null key produces authentication errors only at send time, not at boot.
  • From-address must be on a verified domain. Resend rejects sends from unverified domains; [email protected] is the sandbox address and only delivers to your own account email. If you get 403s locally but not in prod, check which domain is set in MAIL_FROM_ADDRESS.
  • 1.0.0 means "no stability guarantees yet." Watch for 1.0.x patch releases changing behaviour around the transport registration or config keys. Lock the version in composer.json and read the diff before bumping minor versions.
  • Exceptions are usually HTTP. Resend errors surface as response payloads; make sure your Mailable's failed() method or a global Queue::failing handler logs the response body, not just the exception message. You will otherwise chase generic "failed to send" errors.
  • Rate limits bite on bursts. If you fan out newsletters or notifications, chunk your dispatches rather than firing thousands of queued jobs at once — and note that a rate-limit response in a queued Mailable will retry per your queue's tries/backoff settings, which can amplify the problem.
  • Don't mix transports silently. If MAIL_MAILER=resend is set globally but you have mailables built against SendGrid-specific headers or tags, they may be dropped or rejected. Audit any custom withSymfonyMessage() calls when migrating.
  • Extension point to know: the service provider is the place to swap a bound client implementation or add your own transport options. If you need to mock the API in tests, that binding (or the package's config-driven base URL) is what you should override in TestCase::setUp().
  • Publishing tags. Publish only the config tag if the package ships migrations (audiences/contacts mirroring is not a normal pattern — if migrations exist, inspect them before running migrate on a production database).
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource