How to send emails with file attachments using Mailgun API

I’m trying to send emails with file attachments through Mailgun but running into problems. The emails are delivered successfully but the attachments are missing. When I try to include a file path, it just shows the path as text instead of attaching the actual file.

Here’s my current implementation:

$api_key = 'key-7bx9ynkm41hf8gdt6hc485thwkytrel2';
$api_version = 'api.mailgun.net/v3/';
$domain_name = "testing.mailgun.org";
$sender_email = "[email protected]";
$response_email = "[email protected]";

$message_endpoint = "https://".$api_version.$domain_name."/messages";

$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_MAXREDIRS, 5);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_VERBOSE, false);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 15);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);

curl_setopt($curl, CURLOPT_USERPWD, 'api:' . $api_key);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_URL, $message_endpoint);

$post_data = array(
    'from' => 'TestSender <' . '[email protected]' . '>',
    'to' => '[email protected]',
    'h:Reply-To' => ' <' . $response_email . '>',
    'subject' => 'Test Message '.date('Y-m-d'),
    'html' => 'This is a test message with attachment',
    'attachment' => array('document.pdf')
);

curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
$response = curl_exec($curl);
curl_close($curl);

$output = json_decode($response, true);
var_dump($output);

I’ve double checked my Mailgun credentials and they work fine for regular emails. What’s the correct way to attach files when sending through their API?

You’re passing filename strings but Mailgun needs actual file objects. Use curl_file_create() instead - like 'attachment' => curl_file_create('/path/to/document.pdf'). Fixed the same issue for me. Double-check your path though, I wasted hours on wrong paths lol

Your POSTFIELDS setup is the problem. You can’t handle file attachments the same way as regular form data. You need to build multipart data properly instead of just throwing an array at CURLOPT_POSTFIELDS. I hit this exact issue last year - create CURLFile objects first, then build your post array. That’s what actually works. Use absolute file paths, not relative ones. Relative paths fail silently and you’ll go crazy debugging it. Also check your server’s file permissions and upload_max_filesize in PHP config. These settings will drop attachments without any clear error from the API.

You’re passing the filename as a string instead of the actual file data. Mailgun requires the file content as multipart form data, not just the filename. Use CURLFile to fix this: ‘attachment’ => new CURLFile(‘/full/path/to/document.pdf’, ‘application/pdf’, ‘document.pdf’). Ensure you provide the complete server path. For multiple files, simply use an array of CURLFile objects. Also, verify that the file exists and is readable beforehand; otherwise, your email may send but the attachment won’t be included.