phplaraveldnsqueuemailgun

Sending from multiple Mailgun domains using Laravel Mail facade


I'm using the Laravel 4's Mail::queue() to send emails, using the built in Mailgun driver. The problem is that there are multiple Mailgun domains I would like to be able to send emails from, but the domain must be set in app/config/services.php. Since I'm using Mail::queue(), I can't see how to dynamically set that configuration variable.

Is there any way to do what I'm asking? Ideally, I'd like to be able to pass in the domain when I call Mail::queue() (the Mailgun api key is the same for all the domains I want to send from).


Solution

  • Switching the configuration details of the Laravel Mailer at runtime is not that hard, however I don't know of any way it can be done using the Mail::queue facade. It can be done by using a combination of Queue::push and Mail::send (which is what Mail::queue does anyway).

    The problem with the Mail::queue facade is that the $message parameter passed to the closure, is of type Illuminate\Mail\Message and we need to modify the mailer transport, which is only accessible through the Swift_Mailer instance (and that is readonly within the Message class).

    You need to create a class responsible for sending the email, using a Mailgun transport instance that uses the domain you want:

    use Illuminate\Mail\Transport\MailgunTransport;
    use Illuminate\Support\SerializableClosure;
    
    class SendQueuedMail {
    
        public function fire($job, $params)
        {
            // Get the needed parameters
            list($domain, $view, $data, $callback) = $params;
    
            // Backup your default mailer
            $backup = Mail::getSwiftMailer();
    
            // Setup your mailgun transport
            $transport = new MailgunTransport(Config::get('services.mailgun.secret'), $domain);
            $mailer = new Swift_Mailer($transport);
    
            // Set the new mailer with the domain
            Mail::setSwiftMailer($mailer);
    
            // Send your message
            Mail::send($view, $data, unserialize($callback)->getClosure());
    
            // Restore the default mailer instance
            Mail::setSwiftMailer($backup);
        }
    
    }
    

    And now you can queue emails like this:

    use Illuminate\Support\SerializableClosure;
    
    ...
    
    Queue::push('SendQueuedMail', ['domain.com', 'view', $data, serialize(new SerializableClosure(function ($message)
    {
        // do your email sending stuff here
    }))]);
    

    While it's not using Mail::queue, this alternative is just as compact and easy to read. This code is not tested but should work.