Sending email with multiple attachments with PHP

Today I was looking for a cut/paste script to manage emails with multiple attachments with php and I only found classes, server-side libraries or non-working examples (!!!).

I just needed an easy script and I did not find it… so I cut/pasted here and there, I changed something, shaked a bit and here it is an easy and working script.

Just fill $files array with the files to be sent, custom email fields and you’re done.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
 
// array with filenames to be sent as attachment
$files = array("file_1.ext","file_2.ext","file_3.ext",......);
 
// email fields: to, from, subject, and so on
$to = "mail@mail.com";
$from = "mail@mail.com"; 
$subject ="My subject"; 
$message = "My message";
$headers = "From: $from";
 
// boundary 
$semi_rand = md5(time()); 
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x"; 
 
// headers for attachment 
$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\""; 
 
// multipart boundary 
$message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n"; 
$message .= "--{$mime_boundary}\n";
 
// preparing attachments
for($x=0;$x<count($files);$x++){
	$file = fopen($files[$x],"rb");
	$data = fread($file,filesize($files[$x]));
	fclose($file);
	$data = chunk_split(base64_encode($data));
	$message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" . 
	"Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" . 
	"Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
	$message .= "--{$mime_boundary}\n";
}
 
// send
 
$ok = @mail($to, $subject, $message, $headers); 
if ($ok) { 
	echo "<p>mail sent to $to!</p>"; 
} else { 
	echo "<p>mail could not be sent!</p>"; 
} 
 
?>

Enjoy and send mails with any number of attachments without any class/library

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (31 votes, average: 4.29 out of 5)
Loading ... Loading ...
If you found this post useful, please consider a small donation.

37 Responses to “Sending email with multiple attachments with PHP”

  1. Monkios on July 28th, 2008 5:35 pm

    You have to be careful with the mail function.

    Some free hosts disable it.

  2. depi on July 30th, 2008 9:22 pm

    I would also appreciate how to send those mails right from the form – especialy how to attach multiple files and then send them.

  3. Mrinalini on August 6th, 2008 10:08 am

    Hey, its a nice script but how to attach files at run time?

  4. Jina on August 6th, 2008 11:46 am

    A perfect script. I was quite fagged out trying to correct a code sending a single attachment and got no where. Great work.

  5. sasha on August 6th, 2008 2:11 pm

    It would be great to know how to make form for uploading files and storing in this array. I am beginner in PHP. Anyone help, please?

  6. Stephen on August 14th, 2008 10:36 pm

    Thanks for the multiple attachments code. I found what appears to be a problem with it though. For the very last file, I think you need a “–” at the end of the mime boundary hash; i.e., “–{$mime_boundary}–\n”. Otherwise, I get an extra empty file attached to the email called “ATT000??.txt”.

  7. NagaMallesWaraRao on August 28th, 2008 1:56 pm

    Godd Example to send multiple attachment in PHP
    thank you very much for your help

  8. prosenjit das on September 9th, 2008 1:06 pm

    Thank You … It is really helpful for my project … thanx lots ..

  9. jerry on September 19th, 2008 2:58 pm

    hey
    I cant get it to work , what do I need to do with it
    btw I am sort of new to php
    pleas help me anyone

  10. Roxie on September 22nd, 2008 4:41 pm

    The script works great except for one thing.
    I always get an extra file “ATT000XX.txt” that is empty.

    I trying adding “-” to the end of “–{$mime_boundary}”. I added it to just the one in the loop, out of the loop and every combination in between.

    Nothing seems to work.

    How do I get that file to not be attached?

    Thanks.

  11. ioulianos on October 6th, 2008 12:38 pm

    I had the same experience, especially with examples that didn’t work or corrupt attachments, until I found your code.

    Thans a lot !!!

  12. Umesh on November 5th, 2008 12:10 pm

    gr8 work ! but there is problem of extra file “ATT000XX.txt”.

    i found a way in which we can solve this problem as follows;

    $just=count($files);
    for($x=0;$x<count($files);$x++){
    $file = fopen($files[$x],”rb”);
    $data = fread($file,filesize($files[$x]));
    fclose($file);
    $data = chunk_split(base64_encode($data));
    $message .= “Content-Type: {\”application/octet-stream\”};\n” . ” name=\”$files[$x]\”\n” .
    “Content-Disposition: attachment;\n” . ” filename=\”$files[$x]\”\n” .
    “Content-Transfer-Encoding: base64\n\n” . $data . “\n\n”;
    if($x==($just-1))
    {
    $message .= “–{$mime_boundary}-\n”;
    } else
    {
    $message .= “–{$mime_boundary}\n”;
    }

    }

  13. Umesh on November 5th, 2008 12:13 pm

    replace the for loop with this code

    $just=count($files);
    for($x=0;$x<count($files);$x++){
    $file = fopen($files[$x],”rb”);
    $data = fread($file,filesize($files[$x]));
    fclose($file);
    $data = chunk_split(base64_encode($data));
    $message .= “Content-Type: {\”application/octet-stream\”};\n” . ” name=\”$files[$x]\”\n” .
    “Content-Disposition: attachment;\n” . ” filename=\”$files[$x]\”\n” .
    “Content-Transfer-Encoding: base64\n\n” . $data . “\n\n”;
    if($x==($just-1))
    {
    $message .= “–{$mime_boundary}-\n”;
    } else
    {
    $message .= “–{$mime_boundary}\n”;
    }

    }

  14. Niels Bom on February 9th, 2009 4:45 pm

    Line 10 can be skipped because of line 21.

  15. pcsimke on February 19th, 2009 12:12 am

    this worked for me butt i get that extra file

    strange thing in windows mail there is no extra file
    in outlook i got it

    i tray Umesh thing butt then i got only one attachment

    i include 3 of them

  16. Ichah on April 16th, 2009 1:26 pm

    this worked for me butt i get that extra file

    strange thing in windows mail there is no extra file
    in outlook i got it

    i tray Umesh thing butt then i got only one attachment

    i include 3 of them

    instead of –{$mime_boundary}\n this use
    –-{$mime_boundary}–\n

  17. ichha on April 16th, 2009 1:30 pm

    instead of –{$mime_boundary}\n this use
    –-{$mime_boundary}–-\n

  18. Dave on April 24th, 2009 9:39 pm

    I am having issues with multiple attachments. Only the fist one is getting attached while the other files aren’t. Any ideas?

  19. Nick on June 10th, 2009 4:09 am

    I also had issues with an extra attachment, but this did solve the problem:

    Original:
    Line 33:
    $message .= “–{$mime_boundary}\n”;

    FIX:
    $message .= “–{$mime_boundary}–\n”;

  20. Nick on June 10th, 2009 4:10 am

    Hmm, for some reason, WordPress combines 2 hashes “- -” into one hash: “–”

    So to clarify, you want 2 hashes before and after {$mime_boundary}

  21. Mike Engel on June 25th, 2009 9:04 pm

    Thanks Emanuele!!! Great script. Since a lot of people above seem to be having the same problem and I solved said problem, I will show my improved version that worked for me with 0 attachments, 1 attachment and more than 1 attachment without the extra txt file or gibberish at the end. Maybe u can re-post this if u get a chance.

    <?php

    // array with filenames to be sent as attachment

    $files = array("filename.blah", "filename.blah");
    $filecount=count($files);
    // email fields: to, from, subject, and so on
    $to = "blah@blah.com";
    $from = "blah@blah.com";
    $subject ="testemail";
    $message = "testing if the script i downloaded works";
    $headers = "From: $from";

    // boundary
    $semi_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

    // headers for attachment
    $headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";

    // multipart boundary
    $message = "This is a multi-part message in MIME format.\n\n" . "–{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n";
    if($filecount!=0)
    {
    $message .= "–{$mime_boundary}\n";
    }

    // preparing attachments
    for($x=0;$x<$filecount;$x++)
    {

    $file = fopen($files[$x],"rb");
    $data = fread($file,filesize($files[$x]));
    fclose($file);
    $data = chunk_split(base64_encode($data));
    $message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" .
    "Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" .
    "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
    if($x==$filecount-1)
    {
    $message .= "–{$mime_boundary}-\n";
    }

    else
    {
    $message .= "–{$mime_boundary}\n";
    }
    }

    // send
    $ok = @mail($to, $subject, $message, $headers);
    if ($ok)
    {
    echo "mail sent to $to!”;
    }
    else
    {
    echo “mail could not be sent!”;
    }

    ?>

  22. Kapil on June 30th, 2009 8:00 am

    Hi,
    This code works but the initial problem was that it was attaching the empty text file but i used the new code like here specified i replaced the loop with that just variable and even the last code

    <?php

    // array with filenames to be sent as attachment

    $files = array("filename.blah", "filename.blah");
    $filecount=count($files);
    // email fields: to, from, subject, and so on
    $to = "blah@blah.com";
    $from = "blah@blah.com";
    $subject ="testemail";
    $message = "testing if the script i downloaded works";
    $headers = "From: $from";

    // boundary
    $semi_rand = md5(time());
    $mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

    // headers for attachment
    $headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";

    // multipart boundary
    $message = "This is a multi-part message in MIME format.\n\n" . "–{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n";
    if($filecount!=0)
    {
    $message .= "–{$mime_boundary}\n";
    }

    // preparing attachments
    for($x=0;$x

    the extra txt file is removed but it is attaching only one file not all the files name that i gave in the array please provide me the solution for that so that it will attach all the files without extra txt file.

  23. Wilson Abesamis on August 1st, 2009 2:50 am

    Try this it really works on my side.

    $value){
    $ctr_file++;
    $att_file = $_FILES[$idx]['tmp_name'];
    $att_file_type = $_FILES[$idx]['type'];
    $att_file_name = $_FILES[$idx]['name'];

    if (is_uploaded_file($att_file)) {

    // Read the file to be attached (‘rb’ = read binary)
    $file = fopen($att_file,’rb’);
    $data = fread($file,filesize($att_file));
    fclose($file);

    // Base64 encode the file data
    $data = chunk_split(base64_encode($data));

    // Add file attachment to the message
    $message .= “Content-Type: {$att_file_type};\n” .
    ” name=\”{$att_file_name}\”\n” .
    “Content-Disposition: attachment;\n” .
    ” filename=\”{$att_file_name}\”\n” .
    “Content-Transfer-Encoding: base64\n\n” .
    $data . “\n\n”;

    $message .= ($ctr_file != count($_FILES)) ? “–{$mime_boundary}\n” : “–{$mime_boundary}–\n”;
    }
    }

    echo mail($to,$subject,$message,$headers) ? ‘mail sent with attached files’ : ‘mail not sent!’;
    }
    ?>

  24. Srig on August 13th, 2009 1:21 pm

    Simply superb.. its wrkin fine dude…

  25. Swaroop on September 4th, 2009 1:25 pm

    HI, can any one hellp me out, I have mentioned the following code, we are reciving an email with the text format – ATT0029.txt , the following code as mentioned, we are trying to attach a word format and submit

    / Build email data
    // generate a random string to be used as the boundary marker
    $mime_boundary = “==Multipart_Boundary_x”.md5(mt_rand()).”x”;

    // open the file for a binary read
    $file = fopen($this->attachment, ‘rb’);
    // read the file content into a variable
    $data = fread($file, filesize($this->attachment));
    // close the file
    fclose($file);
    // now we encode it and split it into acceptable length lines
    $data = chunk_split(base64_encode($data));
    $file_name = explode(“\\”, $this->attachment );
    // now we’ll build the message headers
    $headers = “From: $from\r\n” . “MIME-Version: 1.0\r\n” . “Content-Type: multipart/mixed;\r\n” . ” boundary=\”{$mime_boundary}\”";
    // next, we’ll build the message body
    // note that we insert two dashes in front of the
    // MIME boundary when we use it
    $message = “This is a multi-part message in MIME format.\n\n” . “–{$mime_boundary}\n” . “Content-Type: text/plain; charset=\”iso-8859-1\”\n” . “Content-Transfer-Encoding: 7bit\n\n” . $message_body . “\n\n”;
    // now we’ll insert a boundary to indicate we’re starting the attachment
    // we have to specify the content type, file name, and disposition as
    // an attachment, then add the file content and set another boundary to
    // indicate that the end of the file has been reached
    $message .= “–{$mime_boundary}\n” . “Content-Type: text/plain;\n” . ” name=\”{$file_name[1]}\”\n” .
    “Content-Disposition: attachment;\n” .
    // ” filename=\”{$fileatt_name}\”\n” .
    “Content-Transfer-Encoding: base64\n\n” . $data . “\n\n” . “–{$mime_boundary}–\n”;

    Please help me out with the solution

  26. danny on September 19th, 2009 3:51 pm

    It doesnt work at all, sometimes it adds 2 attachment other times nothing. The code of Wilson Abesamis is not complete, pls send the complete code

    THanks

    Dabby

  27. jithin on September 23rd, 2009 9:36 am

    works.. but attachment recieves like text

  28. carl on November 8th, 2009 4:17 am

    I made to changes to the original

    replace line 22 with:
    if (count($files)){
    $message .=”–{$mime_boundary}\n”;
    }
    else{
    $message .=”–{$mime_boundary}–\n”;
    }

    replace line 33 with:
    if ($x==count($files)-1){
    $message .=”–{$mime_boundary}–\n”;
    }
    else{
    $message .=”–{$mime_boundary}\n”;
    }

    this handles extra file problem and allows for no files or multiple files to be sent

  29. carl on November 8th, 2009 6:54 am

    Retool here ==You can leave lime 22 as is, but change lime 33 as mentioned above

  30. Kevin on November 16th, 2009 4:33 pm

    How do I name the files to be attached with files which have been uploaded as part of a form to complete the following line?

    (“file_1.ext”,”file_2.ext”,”file_3.ext”,……);

  31. Shaaa on December 14th, 2009 12:29 pm

    Nice Script… :)

  32. Marten Hansson on December 29th, 2009 10:51 pm

    Such a great script! Been testing script on the net for >10hrs without findng what I was looking for. Until now. Thanks from Sweden!

  33. Marten Hansson on December 29th, 2009 10:53 pm

    Oh forgot to say, if you want to send the message in html instead of plain text, just change Content-Type from text/plain to text/html.

  34. john on January 11th, 2010 8:34 pm

    file_get_contents() has been available since php 4.3.0 (release in 2002):

    $data = chunk_split( base64_encode(file_get_contents(“$files[$x]“)) );

  35. Daibhidh on January 15th, 2010 11:15 am

    This looks like a great script and works fine, wit the exception of the extra empty attachment. Lots of people have suggested fixes, but it’s not very clear which fix actually work…would anyone who’s got the script to work be able to post the full amended script on here?

    Many thanks :)

  36. Ovidiu Pop on February 19th, 2010 3:29 pm

    This is my modification which solved for me problem of unwanted file:

    // preparing attachments
    $counted = count($files);
    for($x=0;$x<$counted;$x++){
    $data = chunk_split( base64_encode(file_get_contents("$files[$x]")) );
    $message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" .
    "Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" .
    "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
    if($x < $counted-1){
    $message .= "–{$mime_boundary}\n";
    }else{
    $message .= "–{$mime_boundary}-\n";
    }
    }

Leave a Reply




Trackbacks

  1. MySQL to JSON with PHP : Emanuele Feronato on September 23rd, 2009 11:07 pm

    [...] a everyday use function, but I am sure some of you will find it useful, just like it happened with Sending email with multiple attachments with PHP. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function [...]

flash games company