Laravel Mailgun integration throwing 400 error when attempting to send emails

I’m struggling with email delivery in my Laravel application. After facing difficulties with SendGrid, I switched to Mailgun but I’m still encountering problems. Every time I attempt to send an email, I get a 400 Bad Request error.

My email sending code:

$emailData = [];

Mail::send('emails.verification.welcome', $emailData, function($msg) {
    $msg->to('[email protected]', 'Jane Smith')->subject('Welcome Message');
});

Error message I receive:

GuzzleHttp\Exception\ClientException (400)

Client error response [url] https://api.mailgun.net/v2/mail.mydomain.com/messages.mime [status code] 400 [reason phrase] BAD REQUEST

My mail configuration:

<?php

return [
    'driver' => 'mailgun',
    'host' => 'sandbox123456789.mailgun.org',
    'port' => 587,
    'from' => ['address' => '[email protected]', 'name' => 'MyWebsite'],
    'encryption' => 'tls',
    'username' => '[email protected]',
    'password' => 'mypassword123',
    'sendmail' => '/usr/sbin/sendmail -bs',
    'pretend' => true,
];

What could be causing this 400 error with Mailgun? Any suggestions would be helpful.

Had this exact 400 error six months ago switching from SendGrid to Mailgun. The config mixing issue others mentioned is dead on, but there’s another gotcha that bit me. Laravel with Mailgun driver hits the messages API endpoint, not messages.mime like your error shows. That endpoint usually means your email template’s getting rendered or encoded wrong. Check if your welcome email template exists at emails.verification.welcome and actually renders. I had a busted Blade template throw similar 400s because Mailgun couldn’t parse the MIME structure. Also double-check your APP_ENV isn’t forcing mail pretend mode in your environment config.

Your from address domain mismatch is causing this. You’re sending from ‘[email protected]’ but you’re on the sandbox domain - Mailgun’s picky about that. Also, pretend mode needs to be false for actual sending. Quick fix: either change your from address to match the sandbox domain or verify mysite.com in Mailgun first.

The issue is likely that ‘pretend’ => true in your mail config. That setting’s for testing - Laravel won’t actually send emails, which probably causes your 400 error. Also check your Mailgun setup. When you’re using the Mailgun driver, don’t add host, port, username, and password like you would for SMTP. Just make sure your Mailgun API key and domain are set in services.php with the right environment variables. I ran into the same thing and learned not to mix Mailgun settings with SMTP configs.

The 400 error you’re facing likely stems from incorrect configuration settings. It’s common to encounter issues when mixing Mailgun and SMTP configurations. Ensure that your Mailgun credentials are properly set in services.php rather than mail.php. In your mail.php file, keep only the driver set to ‘mailgun’ along with the from address, and remove any SMTP-related settings like host, port, username, password, and encryption. It’s critical that your from address matches the verified domain on Mailgun. Additionally, make sure the ‘pretend’ mode is set to false in your configuration to enable actual email sending.

Your config has a few problems causing that 400 error. You’re mixing SMTP settings with Mailgun driver - don’t do that. When you use Mailgun driver, skip the host, port, username, password, and encryption stuff in mail.php. Those are SMTP-only. Just make sure your services.php has the right Mailgun API key and domain. Also caught that you’re using a sandbox domain in the host but sending from ‘[email protected]’ - your from domain needs to match your verified Mailgun domain. And check that ‘pretend’ => true setting. That just simulates sending emails instead of actually sending them. Set it to false unless you’re testing.

Look, debugging email delivery issues is exactly why I stopped managing SMTP configs and API integrations manually. Domain mismatches and configuration headaches happen constantly.

Instead of fighting Mailgun’s quirky requirements, I built an automation workflow that handles email delivery through multiple providers with automatic fallbacks. One service breaks? It switches to another instantly.

The workflow monitors delivery rates and adjusts routing based on performance. No more 400 errors ruining user experience. You get detailed logs of every email attempt without digging through Laravel logs.

I’ve run this setup for months and haven’t touched email configs since. The automation handles provider switching, retry logic, and even A/B tests subject lines automatically.

You can build the same workflow here: https://latenode.com