Laravel already has a mail notification channel. You do not need a custom Arawa Mail driver. Return ['mail'] from the notification’s via($notifiable) method, return a MailMessage from toMail(), set MAIL_MAILER=sdp and SDP_EMAIL_KEY, and Laravel Mail posts to Arawa Mail when the notification actually sends. Queued notifications wait for php artisan queue:work.
For example, an invoice notification can use MailMessage and the notifiable’s email route. Returning a full Mailable is also supported, but you must set its recipient explicitly with ->to(...). Omitting that recipient can break the send.
You do not need a custom Arawa Mail notification channel
Laravel Notifications call Laravel Mail for the mail channel. Arawa Mail is the HTTP transport behind that mailer. Install sharasolns/sdp-email, keep package auto-discovery, and leave config/mail.php alone.
composer require sharasolns/sdp-email
MAIL_MAILER=sdp
SDP_EMAIL_KEY=your_api_key
# optional
SDP_EMAIL_ENDPOINT=https://app.arawamail.com
SDP_EMAIL_TIMEOUT=10
The From address must sit on a sending-active domain. Receiving must be active before sending can be enabled. The API key needs the sending scope. A domain-restricted key must allow that From domain. Rebuild config cache in production after changing .env.
Mailbox compose is rate limited per account and is not an application mailer. MCP is not a billing transport. Application notifications use the API key.
How we analyzed this
This guide uses Laravel 12 notification APIs, with the current Laravel 13 documentation linked for comparison; check package compatibility before upgrading. It maps the notification APIs to the current Arawa Mail Laravel quickstart and Send Email API. The HTTP send is immediate POST /emails with from, to, subject, html/text, cc, bcc, reply_to, headers, and attachments. There is no scheduledAt field. Competitor APIs that accept a provider-side schedule are not a substitute here. Delay in Laravel, then send.
A complete InvoicePaid notification
Put ShouldQueue on the notification class so one job is queued per notifiable per channel. MailMessage uses the notifiable’s routing. If returning a Mailable, populate its recipient explicitly, for example return (new InvoicePaidMailable($invoice))->to($notifiable->email);. For anonymous notifiables use $notifiable->routeNotificationFor('mail').
namespace App\Notifications;
use App\Models\Invoice;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
public function __construct(public Invoice $invoice) {}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Invoice '.$this->invoice->number.' paid')
->greeting('Payment received')
->line('We recorded payment for invoice '.$this->invoice->number.'.')
->action('View invoice', $this->invoice->signedUrl())
->line('Reply to this message if the amount looks wrong.');
}
}
Dispatch from the paid event:
$user->notify(new InvoicePaid($invoice));
The recipient comes from routeNotificationForMail() on the notifiable, or from the model's email attribute. That is why a User works and a raw array does not.
Anonymous notifiables: email an address that is not a User
Leads and trial contacts often have no User row. Route the mail channel to a raw address:
use Illuminate\Support\Facades\Notification;
Notification::route('mail', $lead->email)
->notify(new TrialEnding($trial));
Password reset notifications already use this stack. Keep the notification class. Switch the mailer to sdp. Do not rewrite them as mailables unless you want two send paths.
ShouldQueue on the notification, not a pasted mailable
Queue the notification class. Laravel then queues one job per notifiable per channel. The HTTP call to Arawa Mail happens when the worker runs, not when the request returns. API-originated mail is written to Sent after that HTTP call succeeds. Admins will not see the message in Sent until php artisan queue:work has processed the job.
Firing queued notifications from a web request with no worker is the usual “nothing sent” failure. Worker setup, afterCommit, and mailable queues belong in Queue Laravel Mailables with ShouldQueue.
Caveat: Arawa Mail POST /emails has no scheduled-send field. If the receipt must wait until Friday, delay the Laravel job or notification. Do not invent scheduled_at on the API body.
What this is not
- Not a first-send mailable walkthrough. That lives in Send email in Laravel.
- Not Mail::raw for ad-hoc strings.
- Not provider SMTP. If you are choosing transports, read SMTP vs Email API.
- Not MCP. Assistants can help humans in a mailbox. They should not be the invoice mailer.
After send, delivery events can be handled with transactional email webhooks. Current sending limits and mailbox plans are on the live pricing page.
FAQ
Do I need a custom Arawa Mail notification channel?
No. Use Laravel’s built-in mail channel. Arawa Mail is reached because MAIL_MAILER=sdp.
Where does toMail() get the recipient?
From routeNotificationForMail() or the notifiable email attribute. Anonymous routes set the address with Notification::route('mail', $email).
Should the notification or the mailable implement ShouldQueue?
Implement ShouldQueue on the notification class for this path. That queues one job per notifiable per channel.
Will a queued notification appear in Sent immediately?
No. Sent is written when the HTTP API send completes. That is after the worker runs.
Can MCP send these receipts?
No. Use the mail channel and a sending-scoped API key.
Sources and review
Reviewed against the linked documentation on 3 October 2026. Examples are illustrative; code that depends on application models must be adapted and tested in your own project.