Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

Configuring Mail Failover and Fallback Transports in Laravel

When Laravel code sends transactional email, an outage at a mail provider can stop Laravel from handing off messages such as password resets or order confirmations. Laravel’s failover transport lets you set a preferred mailer and an ordered list of alternatives. If one transport fails, Laravel tries the next one.

A transport is the route Laravel uses to send a message, such as a provider’s API or an SMTP connection. Failover gives Laravel another route to try when an earlier route fails. This increases the chance that a provider will accept the message, but it does not guarantee that the message reaches the recipient’s inbox.

Configure mailers in fallback order

In config/mail.php, define a separate mailer for each provider or sending route. Then define a mailer that uses the failover transport and lists the other mailers in the order Laravel should try them. Laravel’s 13.x mail documentation shows this pattern:

// config/mail.php

'mailers' => [
    'postmark' => [
        'transport' => 'postmark',
        // Add the provider credentials and other settings.
    ],

    'mailgun' => [
        'transport' => 'mailgun',
        // Add the provider credentials and other settings.
    ],

    'sendmail' => [
        'transport' => 'sendmail',
    ],

    'failover' => [
        'transport' => 'failover',
        'mailers' => [
            'postmark',
            'mailgun',
            'sendmail',
        ],
        'retry_after' => 60,
    ],
],

'default' => env('MAIL_MAILER', 'failover'),

Here, postmark is the primary route. If that attempt fails, Laravel tries mailgun; if that attempt also fails, Laravel tries sendmail. Set MAIL_MAILER=failover in the environment to make Laravel use this configuration by default. Each mailer in the list needs valid settings and credentials for its transport.

Laravel’s 13.x example includes retry_after set to 60, but that value should not be treated as a universal promise that failover happens after a 60-second delay. The Laravel 11.x example shows the ordered mailer list without that option, so check the documentation for the Laravel version you run. Symfony documents a retry_period option for its failover transport, but that Symfony setting is distinct from Laravel’s retry_after configuration key.

Choose fallbacks for the failures you need to handle

Choose the primary route for normal sending, then select fallbacks that can handle the same messages when the primary route fails. Symfony Mailer, which powers Laravel’s mailer, describes the failover sequence: it starts with the first transport and tries the next transport after a failure, continuing until a transport succeeds or the available transports run out. See the Symfony Mailer failover behavior.

A fallback works best when it does not rely on the same part that is likely to fail as the primary route. For example, two mailers that rely on the same provider or credentials may fail together. When choosing alternatives, check which provider, connection type, infrastructure, and credentials each route depends on. Laravel supports different mail transports, but providers do not necessarily offer the same features. Confirm that every route supports the sender identity, message content, and attachments your code sends.

The sendmail mailer in the example works as a fallback only if the server running the Laravel code has a working sendmail route that can deliver the intended messages. Adding a name to the configuration does not make the route available or independent.

Laravel documents round robin separately from failover. Round robin distributes messages across configured mailers; failover tries the preferred mailer first and moves to another after a failure. Choose round robin when you want to spread sends across routes, and failover when you want a primary route with backups. Laravel’s mail configuration documentation covers both transports.

Know what a successful send means

Failover covers the handoff from Laravel to a mail transport. When a provider accepts a message for processing, Laravel treats that handoff as successful. The provider can still fail to deliver the message later, or a receiving mail service can filter it. Symfony’s Mailer documentation explains this limit: the sending application cannot confirm every later step in delivery.

An uncertain handoff can also lead to duplicate sends. A provider might accept a message while Laravel encounters an error before receiving confirmation. The available documentation does not promise that Laravel will send exactly one copy in that situation. Consider whether duplicate transactional messages would cause harm, and design any surrounding retry or idempotency logic with that risk in mind.

Queueing mail addresses a different concern. Laravel queues mail so a worker running in the background can send it outside the request that triggered the message. Failover serves a different purpose: Laravel tries another transport after a sending attempt fails. A queue can complement failover, but it does not replace the fallback configuration. Laravel describes queued mail separately from transport failover.

Test each route before relying on it

Send test messages through each configured mailer and confirm that the fallback routes can send the same kinds of messages as the primary route. Then test what happens when the primary transport fails, and monitor which route handles real messages. Check the provider credentials and setup for every mailer; a configuration that loads successfully does not prove that its transport can send.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *