Search code examples
phpemailemail-attachments

PHP email attachments have still 0 kb


For some reason my PHP mail script constantly sends attachments as 0 kb despite I am paying attention to correct number of empty lines as was told in many similar answers around Stackoverflow.

Basically, they said there that "...supposed to be a blank line between the attachment header and the attachment contents" which I guess I got right - or not?.

But maybe I am missing something else here - can anyone tell me what is wrong with the code, that is: why it sends email attachments as of size 0 kb still?

This is the important part of the script:

for($i = 0; $i < count($_FILES['filename']['name']); $i++){
    $tmp_name = $_FILES['filename']['tmp_name'][$i];
    if (file_exists($tmp_name)){
        $fname[] = $_FILES['filename']['name'][$i];
    }
}

// array with filenames to be sent as attachment
$files = $fname;

$msg = '<b>E-mail:</b> some@email.here<br>';
$msg .= 'Some other text here...<br>';
$msg .= '<br><br><br>';

// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
    
$headers = "From: $from";
$headers .= "\nMIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;\r\n";
$headers .= " boundary=\"{$mime_boundary}\"";

// multipart boundary
$message = "This is a multi-part message in MIME format.\n\n";
$message .= "--{$mime_boundary}\n";
$message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: 7bit\n\n";
$message .= $msg . "\n\n";
$message .= "--{$mime_boundary}\n";
    
// preparing attachments
for($i = 0; $i < count($files); $i++){
        
    $file = fopen($files[$i], "rb");
    $data = fread($file, filesize($files[$i]));
    fclose($file);
    
    $data = chunk_split(base64_encode($data));
    
    $message .= "Content-Type: {\"application/octet-stream\"}; name=\"$files[$i]\"\r\n";
    $message .= "Content-Transfer-Encoding: base64\r\n";
    $message .= "Content-Disposition: attachment; filename=\"$files[$i]\"\r\n\r\n";
    $message .= $data."\r\n\r\n";
    $message .= "--{$mime_boundary}\r\n\r\n";
}

// send
if(@mail($to, $subject, $message, $headers)){
    echo "ok";
}

UPDATE:

So, the actual problem was in the 1st for() loop, where instead of "$fname[] = $_FILES['filename']['name'][$i];" it should be "$fname[] = $_FILES['filename']['tmp_name'][$i];", as that was producing just the name instead of the full path to the file, therefore my files was alwyas 0kb. That said, this works:

for($i = 0; $i < count($_FILES['filename']['name']); $i++){
    $tmp_name = $_FILES['filename']['tmp_name'][$i];
    if (file_exists($tmp_name)){
        $fname[] = $_FILES['filename']['tmp_name'][$i];
    }
}

// array with filenames to be sent as attachment
$files = $fname;

$msg = '<b>E-mail:</b> some@email.here<br>';
$msg .= 'Some other text here...<br>';
$msg .= '<br><br><br>';

// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
    
$headers = "From: $from";
$headers .= "\nMIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;\r\n";
$headers .= " boundary=\"{$mime_boundary}\"";

// multipart boundary
$message = "This is a multi-part message in MIME format.\n\n";
$message .= "--{$mime_boundary}\n";
$message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: 7bit\n\n";
$message .= $msg . "\n\n";
$message .= "--{$mime_boundary}\n";
    
// preparing attachments
for($i = 0; $i < count($files); $i++){
        
    $file = fopen($files[$i], "rb");
    $data = fread($file, filesize($files[$i]));
    fclose($file);
    
    $data = chunk_split(base64_encode($data));
    
    $message .= "Content-Type: {\"application/octet-stream\"}; name=\"$files[$i]\"\r\n";
    $message .= "Content-Transfer-Encoding: base64\r\n";
    $message .= "Content-Disposition: attachment; filename=\"$files[$i]\"\r\n\r\n";
    $message .= $data."\r\n\r\n";
    $message .= "--{$mime_boundary}\r\n\r\n";
}

// send
if(@mail($to, $subject, $message, $headers)){
    echo "ok";
}

BUT NOW ANOTHER PROBLEM: now files have correct size but instead have wrong names without any extension - how to solve this? Should I define new variable just for the file names or could they be somehow taken from the $fname?

UPDATE 2:

So far I've managed to make it work, but only partially in the sense that only the 1st file in attachment is shown as it should but any other file is shown as long text full of letters and numbers - why? This is the script that partially work for me so far:

for($i = 0; $i < count($_FILES['filename']['name']); $i++){
    $tmp_name = $_FILES['filename']['tmp_name'][$i];
    if (file_exists($tmp_name)){
        $fpath[] = $_FILES['filename']['tmp_name'][$i];
        $fname[] = $_FILES['filename']['name'][$i];
    }
}

$msg = '<b>E-mail:</b> some@email.here<br>';
$msg .= 'Some other text here...<br>';
$msg .= '<br><br><br>';

// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
    
$headers = "From: $from";
$headers .= "\nMIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed;\r\n";
$headers .= " boundary=\"{$mime_boundary}\"";

// multipart boundary
$message = "This is a multi-part message in MIME format.\n\n";
$message .= "--{$mime_boundary}\n";
$message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: 7bit\n\n";
$message .= $msg . "\n\n";
$message .= "--{$mime_boundary}\n";
    
// preparing attachments
for($i = 0; $i < count($fpath); $i++){
        
    $file = fopen($fpath[$i], "rb");
    $data = fread($file, filesize($fpath[$i]));
    fclose($file);
    
    $data = chunk_split(base64_encode($data));
    
    $message .= "Content-Type: {\"application/octet-stream\"}; name=\"$fpath[$i]\"\r\n";
    $message .= "Content-Transfer-Encoding: base64\r\n";
    $message .= "Content-Disposition: attachment; filename=\"$fname[$i]\"\r\n\r\n";
    $message .= $data."\r\n\r\n";
    $message .= "--{$mime_boundary}\r\n\r\n";
}

// send
if(@mail($to, $subject, $message, $headers)){
    echo "ok";
}

Solution

  • Once again I had to come to the solution myself! Well, it turned out to be problem of just 2 things:

    • wrongly defined file path from files to be attached
    • wrongly placed boundary section for attached files

    This is the final correct code that works for me beautifully:

    for($i = 0; $i < count($_FILES['filename']['name']); $i++){
        $tmp_name = $_FILES['filename']['tmp_name'][$i];
        if (file_exists($tmp_name)){
            $fpath[] = $_FILES['filename']['tmp_name'][$i];
            $fname[] = $_FILES['filename']['name'][$i];
        }
    }
    
    $msg = '<b>E-mail:</b> some@email.here<br>';
    $msg .= 'Some other text here...<br>';
    $msg .= '<br><br><br>';
    
    // boundary
    $semi_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
        
    $headers = "From: $from";
    $headers .= "\nMIME-Version: 1.0\r\n";
    $headers .= "Content-Type: multipart/mixed;\r\n";
    $headers .= " boundary=\"{$mime_boundary}\"";
    
    // multipart boundary
    $message = "This is a multi-part message in MIME format.\n\n";
    $message .= "--{$mime_boundary}\n";
    $message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
    $message .= "Content-Transfer-Encoding: 7bit\n\n";
    $message .= $msg;
    
    // preparing attachments
    for($i = 0; $i < count($fpath); $i++){
        
        $file = fopen($fpath[$i], "rb");
        $data = fread($file, filesize($fpath[$i]));
        fclose($file);
        
        $data = chunk_split(base64_encode($data));
        
        
        $message .= "\r\n--{$mime_boundary}\r\n";
        $message .= "Content-Type: {\"application/octet-stream\"}; name=\"$fpath[$i]\"\r\n";
        $message .= "Content-Transfer-Encoding: base64\r\n";
        $message .= "Content-Disposition: attachment; filename=\"$fname[$i]\"\r\n\r\n";
        $message .= $data;
    }
    
    $message .= "\r\n--{$mime_boundary}--";
    
    // send
    if(@mail($to, $subject, $message, $headers)){
        echo "ok";
    }