Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/yugo412/laravel-maily/llms.txt

Use this file to discover all available pages before exploring further.

Laravel Maily throws two distinct exception types depending on the failure mode. Understanding which exception to expect at each stage of the send lifecycle helps you write resilient mail-sending code, surface meaningful error messages to operators, and debug issues quickly without guesswork.

Exception types

MailyException

Thrown for configuration and validation errors detected before the API is contacted — such as a missing API key or an attempt to send to multiple recipients.Extends PHP’s built-in Exception.

MailyTransportException

Thrown for HTTP and connection failures that occur while communicating with the Maily API — such as non-2xx responses, validation rejections from the server, or network timeouts.Extends Symfony’s TransportException.

MailyException

Class: Yugo\Maily\Exceptions\MailyException — extends Exception This exception is thrown early in the send process, before any network request is made. It indicates a problem with your application’s configuration or the arguments passed to the mail call. It is thrown in two situations:
  • Missing API key — the services.maily.key config value is empty or not set:
    “Missing Maily API key. Please set services.maily.key configuration.”
  • Multiple recipients — more than one address is passed to ->to():
    “Maily currently only supports a single recipient.”
Catch MailyException to detect and recover from these configuration-level problems:
use Yugo\Maily\Exceptions\MailyException;

try {
    Mail::to($user)->send(new WelcomeMail());
} catch (MailyException $e) {
    // Configuration issue — check MAILY_KEY in .env
    logger()->error('Maily config error', ['message' => $e->getMessage()]);
}
Because these errors stem from misconfiguration rather than transient conditions, retrying the same call without fixing the underlying issue will not help.

MailyTransportException

Class: Yugo\Maily\Exceptions\MailyTransportException — extends Symfony’s TransportException This exception is thrown when communication with the Maily API fails after the transport has attempted to send the request. It covers three scenarios:
  • Non-2xx API response — the Maily API returns an HTTP error status. The exception message includes the HTTP status code and the error detail from the response body:
    “Maily API request failed with status 403: Domain not registered for this account”
  • Server-side validation failure — the API returns a 422 (or similar) with a details array. The exception message is augmented with field-level detail (see Validation error format):
    “Maily API request failed with status 422: Validation failed: to: Invalid to address”
  • Connection failure — the transport cannot reach the Maily API after all configured retries are exhausted:
    “Could not connect to the Maily API.”
Catch MailyTransportException to handle API and network failures gracefully:
use Yugo\Maily\Exceptions\MailyTransportException;

try {
    Mail::to($user)->send(new WelcomeMail());
} catch (MailyTransportException $e) {
    // API or network failure
    logger()->error('Maily transport error', ['message' => $e->getMessage()]);
}

Validation error format

When the Maily API returns a response body that includes a details array, the transport appends a formatted, human-readable breakdown of each field-level error to the exception message. This makes it straightforward to identify exactly which field failed validation without inspecting the raw response body. The relevant code from MailyTransport:
if ($details = $response->json('details')) {
    $detailMessage = collect($details)
        ->map(function (array $detail): string {
            return sprintf('%s: %s', $detail['field'] ?? 'unknown', $detail['message'] ?? 'Unknown error');
        })
        ->implode(', ');
    $message .= ': ' . $detailMessage;
}
For example, an API response of:
{
  "error": "Validation failed",
  "details": [
    { "field": "to", "message": "Invalid to address" }
  ]
}
…produces the exception message:
Maily API request failed with status 422: Validation failed: to: Invalid to address
When multiple fields fail, the details are comma-separated: field1: message1, field2: message2.

Retry behavior on connection errors

A MailyTransportException for connection failures is only thrown after all retries are exhausted. By default, retries are disabled (MAILY_RETRY=0). Configure the number of retry attempts via the MAILY_RETRY environment variable and the delay between attempts (in milliseconds) via MAILY_RETRY_DURATION.
MAILY_RETRY=3
MAILY_RETRY_DURATION=1000
API errors (non-2xx responses) are NOT retried. The retry mechanism is triggered only by ConnectionException — that is, when the transport cannot establish a connection to the Maily API at all (network outage, DNS failure, timeout before a response is received). If the API returns a 4xx or 5xx status code, the MailyTransportException is thrown immediately without any retry attempts.

Build docs developers (and LLMs) love