Sending emails with attachments using PHP’s mail() function

Update 2009/11/19: Some readers emailed me to mention that the script below doesn’t always work properly on all platforms (email messages are sometimes received with attachments but no content, or are sometimes completely blank). If the script below doesn’t work for you, Geekology has another post that details a method of sending emails with attachments in a PHP script that makes use of an external library.

If you need to send an email with attachments using just PHP’s mail() function, you can do so by using a multipart/mixed content header and converting the attachments to base64 strings.

First, generate a random hash to serve as a MIME Boundary:

$random_hash = md5(date('r', time()));

Next, set some email headers:

$headers = "From: noreply@geekology.co.za\r\nReply-To: noreply@geekology.co.za";
$headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";

… then convert the attachment into a base64 string:

$attachment = chunk_split(base64_encode(file_get_contents("geekology.zip")));

Finally, define the content of the email similar to the example below, then send it using PHP’s mail() function:

<?php
 
  $to = "willem@geekology.co.za";
 
  $subject = "A test email";
 
  $random_hash = md5(date('r', time()));
 
  $headers = "From: noreply@geekology.co.za\r\nReply-To: noreply@geekology.co.za";
 
  $headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";
 
  $attachment = chunk_split(base64_encode(file_get_contents("geekology.zip")));
 
  $output = "
--PHP-mixed-$random_hash;
Content-Type: multipart/alternative; boundary='PHP-alt-$random_hash'
--PHP-alt-$random_hash
Content-Type: text/plain; charset='iso-8859-1'
Content-Transfer-Encoding: 7bit
 
Hello World!
This is the simple text version of the email message.
 
--PHP-alt-$random_hash
Content-Type: text/html; charset='iso-8859-1'
Content-Transfer-Encoding: 7bit
 
<h2>Hello World!</h2>
<p>This is the <b>HTML</b> version of the email message.</p>
 
--PHP-alt-$random_hash--
 
--PHP-mixed-$random_hash
Content-Type: application/zip; name=geekology.zip
Content-Transfer-Encoding: base64
Content-Disposition: attachment
 
$attachment
--PHP-mixed-$random_hash--";
 
  echo @mail($to, $subject, $output, $headers);
 
?>

 

Related posts:

  1. A simpler way to send Text or HTML emails with attachments in PHP
  2. Forcing a Return-Path header when sending email with PHP’s mail() function
  3. Testing SMTP servers from a UNIX command line
  4. Validating and sanitizing URLs, Emails, and other inputs with PHP’s filter_* functions
  5. Sending Tweets from the command line using a Bash script
Twitter Digg Delicious Stumbleupon Technorati Facebook Email

32 Responses to “Sending emails with attachments using PHP’s mail() function”

  1. After scratching my head for a while I came across this and the attachment works. Only one I could find that deals with the attachment correctly, thanks. The only problem is that I cannot get the text or html version of the body to show up in the actual email. Any thoughts?

    Thanks,

    Eric

  2. Hi Eric

    The exact structure of the header contents (including the amount and position of linebreaks) are very important.

    I assume it’s you that sent the test messages to me from the info@… address? In those messages, spaces were added before the raw header content lines. Could you please update your script to start with the initial linebreak after ‘$output = “‘ that I use above, not add any spaces before the raw lines following it, then send me a test again?

    Thanks!

  3. Hi there, I used the above code to send mail with attachment. Now i can able to receive a mail with attachment, but if i attach a text file, while try to open it after downloading from mail, it has no content. If i tried to open jpg file attachment then it shows “No Preview available”. I don’t know where i did mistake. If anyone know the solution, please help me for this issue.

  4. Be sure you have the line spaces just as you see them in the code. They make the difference. If you condensed the code down to get rid of extra lines then it won’t work. The attachments will go through but will end up corrupt. So be sure to leave the spaces in as you see them.

    Hope this helps.

  5. Thank you very much Eric. The code works now. Thanks a lot…

  6. Hi

    I have been trying your code since friday and the attachment works fine but the email dont display ant message body. I tried doing what you said about the exact header contents but still no luck please advice

  7. Hai ,
    Use this code in your php file.

    $to = 	'xx@yahoo.com';
    $subject = 	'PHP Mail Attachment Test';
     
    $bound_text = 	"jimmyP123";
     
    $bound = 	"--".$bound_text."\r\n";
     
    $bound_last = 	"--".$bound_text."--\r\n";
     
    $headers = 	"From: xxx@example.com\r\n";
    $headers .= "MIME-Version: 1.0\r\n"
      	."Content-Type: multipart/mixed; boundary=\"$bound_text\"";
     
    $message .= 	"If you can see this MIME than your client doesn't accept MIME types!\r\n"
      	.$bound;
     
     
    $message .= 	"Content-Type: text/html; charset=\"iso-8859-1\"\r\n"
      	."Content-Transfer-Encoding: 7bit\r\n\r\n"
    	."hai\r\n"
    	.$value
    	.$bound;
     
    $file = 	file_get_contents($target_path);
     
    name=\"attachment.doc\"\r\n"
    $message .= 	"Content-Type: application/msword; name=\"attachment.doc\"\r\n"
      	."Content-Transfer-Encoding: base64\r\n"
      	."Content-disposition: attachment; file=\"attachment.doc\"\r\n"
      	."\r\n"
      	.chunk_split(base64_encode($file))
      	.$bound_last;
     
    if(mail($to, $subject, $message, $headers))
    {
         echo 'MAIL SENT SUCCESSFULLY';
    } else {
         echo 'MAIL SENDING FAILED';
    }
  8. Hi Willem

    You are probably inudated with questions about your script and thats because it’s the only script inexperienced webber like me can follow.

    I do though have two questions:
    1) The attachments is attached to the email OK, but the attachment file size is Zero, i.e. there is no content to the zip, even though my file Attach. zip is 125K
    2) How can I send my text content using your example? I have a pretty large form that needs to be complete and I need to perform some logic before sending the data.

    Using your excellent scrip, I have put together an example for you, your comments and guidence will be gratefully appreciated.

    "1") {
    $message.=" has a CSCS reference of ";
    $message.= $_POST["CSCS"];
    $message.=" \n\n";
    }
    else {
    $message.=" does not have a CSCS reference \n\n ";
    }
    $message.= $_POST["FirstName"];
    $message.=" ";
    $message.= $_POST["LastName"];
    if ($cpcs &gt;"1") {
    $message.=" has a CPCS reference of ";
    $message.= $_POST["CPCS"];
    $message.=" \n\n";
    }
    else {
    $message.=" does not have a CPCS reference \n\n";
    }
    $message.= $_POST["FirstName"];
    $message.=" ";
    $message.= $_POST["LastName"];
    $message.=" is currently working for ";
    $message.= $_POST["ContractName"];
    $message.=" and will be available for work on ";
    $message.= $_POST["Day"] ;
    $message.=" ";
    $message.= $_POST["Date"] ;
    $message.=" ";
    $message.= $_POST["Month"] ;
    $message.=" ";
    $message.= $_POST["Year"] ;
    $message.="\n\n";
    //end of my text sample
    "
     
    --PHP-alt-$random_hash
    Content-Type: text/html; charset='iso-8859-1'
    Content-Transfer-Encoding: 7bit
     
    Hello World!
    This is the <b>HTML</b> version of the email message.
     
    --PHP-alt-$random_hash--
    --PHP-mixed-$random_hash
    Content-Type: application/zip; name=Attach.zip
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment
     
    $attachment
    --PHP-mixed-$random_hash--";
     
      echo @mail($to, $subject, $output, $headers);
     
    ?>
  9. Hi Martin

    The blog software is probably stripping out some characters from your example, could you please email the script file to me at willem@geekology.co.za and I’ll take a look?

  10. Im using your script. If file is already exists in a folder then your code is working fine.

    If im generating the .zip files dynamically its not working.

    May i know what is the reason

  11. If you are creating the file to be mailed it should work fine. Are you 100% sure the file has the correct name and the extension is the proper one? Also, are you sure the application type is correct? I do this now with databases. I have them created on the fly and send them out. It does not have a problem. Make sure the name of the file you are creating are set with a variable. Then use the variable where it is needed in the mail. My feeling is that you’re not getting the file in the email but are getting the email. If so then it is the naming.

    Hope this makes sense,

    Eric

  12. Hi all,
    I am new to php and i am trying to send email with pdf file as attachment,above code.Now i can able to receive a mail with attachment,but i got message as adobe reader
    could not open file because it is either not supportted filetype or file has been damaged.
    here i am pasting code.please help me.
    $to = “ramesh.naga@honeywell.com”;

    $subject = “A test email”;

    $random_hash = md5(date(‘r’, time()));

    $headers = “From: ramesh.naga@honeywell.com\r\nReply-To: noreply@geekology.co.za“;

    $headers .= “\r\nContent-Type: multipart/mixed; boundary=\”PHP-mixed-”.$random_hash.”\”";

    $attachment = chunk_split(base64_encode(file_get_contents(“ramesh.pdf”)));

    $output = ”
    –PHP-mixed-$random_hash;
    Content-Type: multipart/alternative; boundary=’PHP-alt-$random_hash’
    –PHP-alt-$random_hash
    Content-Type: text/plain; charset=’iso-8859-1′
    Content-Transfer-Encoding: 7bit

    Hello World!
    This is the simple text version of the email message.

    –PHP-alt-$random_hash
    Content-Type: text/html; charset=’iso-8859-1′
    Content-Transfer-Encoding: 7bit

    Hello World!
    This is the HTML version of the email message.

    –PHP-alt-$random_hash–

    –PHP-mixed-$random_hash
    Content-Type: application/pdf; name=ramesh.pdf
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment

    $attachment
    –PHP-mixed-$random_hash–”;

    echo @mail($to, $subject, $output, $headers);

    ?>

  13. After some frustration, I was able to get this working. Seems there were some issues with the boundaries as defined above. My code is as follows:

    $to = ‘user@domain.com’;
    $subject = ‘Test email message’;
    $random_hash = md5(date(‘r’, time()));
    $headers = “From: sender@domain.com\r\nReply-To: sender@domain.com\r\n”;
    $headers .= “Content-Type: multipart/mixed; boundary=\”PHP-mixed-”.$random_hash.”\”";
    $attachment = chunk_split(base64_encode(file_get_contents($pdfFilename)));
    $output = ”
    –PHP-mixed-$random_hash
    Content-Type: text/plain; charset=’iso-8859-1′

    This is the simple text version of the email message.

    –PHP-mixed-$random_hash
    Content-Type: text/html; charset=’iso-8859-1′

    This is the simple text version of the email message.

    –PHP-mixed-$random_hash
    Content-Type: application/pdf; name=$pdfFilename
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment

    $attachment
    –PHP-mixed-$random_hash–”;

    if (@mail($to, $subject, $output, $headers)) {
    echo ‘Mail sent’;
    } else {
    echo ‘Mail NOT sent’;
    }
    var_dump($headers, $output);

  14. I found a similar link at http://www.webcheatsheet.com/php/send_email_text_html_attachment.php.

    I tried using the one you gave here which works perfectly till i open the attachment. Im not sure if directly copying and pasting code from a browser to my development software ( Dreamweaver CS3 ) adds any additional whitespace | extra characters.

    Thanks for the help :)

  15. hi there, first off thank you for the script. i have struggled with attaching files to emails using mail() for quite some time.

    i’ve copied your script exactly, changing only the $to variable and the “From” section to contain my email addresses. i have not added/removed spacing or modified the structure.

    i’m happy to report that i received the attachment and was able to read it, download it, etc. without error. the problem is that neither the plain text nor the html text shows up in the email. i read your response above about the spacing/structure having to match exactly but since i copied your script directly, have not modified its spacing/structure, and am receiving the attachments, i think there is something else wrong.

    when i viewed the full headers (in gmail), the plain text and html text was included but it does not show up in the regular email. even a view source does not contain the text.

    any help you could provide will be greatly appreciated. thank you!

  16. After days of frustration, I’ve finally found my answer.

    Great post–Thanks a ton for the help!!!

  17. I wasn’t able to get the body of the message to appear. After some trial and error i found the problem to be in the top of the message body in this posting.

    $output = ”
    –PHP-mixed-$random_hash;
    Content-Type: multipart/alternative; boundary=’PHP-alt-$random_hash’

    The boundary string is wrapped in single quotes. When i changed them to double quotes (/”) then my message body came through ok.

  18. i have the same problem the html text body it doesnt show at alla any ideas

  19. Hi,

    I want to send the pdf file as an attachment instead of zip file.

    I changed the file name and apllication/pdf in ContentType.

    I received the mail with an attachment but when I tried to open the attach pdf. It gives error.

    “Adobe Reader could not open ‘filename.pdf’ because it is either not a supported file type or because the file has been damaged(for example, it was send as an email attachment and wasn’t correctly decoded).”

    Any idea?

    Thanks in advance.

  20. Hi.

    When i post a message to my address via this script, i get dozens of paragraphs like this :

    /9j/4AAQSkZJRgABAgEAYABgAAD/4RA2RXhpZgAATU0AKgAAAAgABwEyAAIAAAAUAAAAYkdGAAMA…

    I tried too many times and i could not get it worked.

    Please help…

  21. Hello R. Canser

    I had the same problem with the attachment showing up as characters in the mail body.

    Try to delete the “\r” in the headers it worked for me.

    $headers = “From: $from\r\n” .
    “MIME-Version: 1.0\r\n” .
    “Content-Type: multipart/mixed;\r\n” .
    ” boundary=\”{$mime_boundary}\”";

  22. OMG Tilapic you made my day! I had the same problem as R. Canser and you trick works. I would never have tought of trying that… Do you know why we need to remove the “\r”??

  23. I found the problem, there is a ; that is not needed ont he first line which start by –PHP-mixed

    also, when we copy paste, the is some unwanted space that add at the end of some lines. It’s VERY important that the lines starting with –PHP-mixed or –PHP-alt have no space at the end.

    I remove the ; and the unwanted extra spaces and converted all the ‘ to ” for charset and boundary, then the code worked as is.

    Good luck.

  24. Thanks for your post Willem! Very helpful.

    I too had to change ‘ into ” to make it work 100% or else mail body was not displayed.

  25. I have changed the code slightly and the message body is not appearing still even after changing ‘ to ” on all counts. Any ideas guys??

    Heres my code:

    $filename = $_FILES["file"]["name"];
    $random_hash = md5(date(‘r’, time()));
    $headers = “From: “.$sys_generalemailfull;
    $headers .= “\r\nContent-Type: multipart/mixed; boundary=\”PHP-mixed-”.$random_hash.”\”";

    $attachment = chunk_split(base64_encode(file_get_contents($filename)));

    $output = ”
    –PHP-mixed-$random_hash;
    Content-Type: multipart/alternative; boundary=\”PHP-alt-”.$random_hash.”\”
    –PHP-alt-$random_hash
    Content-Type: text/plain; charset=\”iso-8859-1\”
    Content-Transfer-Encoding: 7bit

    “.$_REQUEST["content"].”

    –PHP-alt-$random_hash
    Content-Type: text/html; charset=\”iso-8859-1\”
    Content-Transfer-Encoding: 7bit

    “.$_REQUEST["content"].”

    –PHP-alt-$random_hash–

    –PHP-mixed-$random_hash
    Content-Type: “.$_FILES["file"]["type"].”; name=”.$filename.”
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment

    $attachment
    –PHP-mixed-$random_hash–”;

  26. Hi, after scratching my head under pressure for 2 days, your code has was the only recovery for me…Thx for the code dude.

  27. Hi, after scratching my head under pressure for 2 days, your code has was the only recovery for me, now I can customize for my need…Thx for the code dude.

  28. Hello;)
    Scirpt works very fine! I can send even few attachments but there is a problem with text files. When I try send for example ‘file.txt’ as an attachment I get random chars inside the file. What could be the problem?

  29. Ok I’m trying it too now..

Trackbacks/Pingbacks

  1. XkiD | Sending emails with attachments using PHP’s mail() function | blog.xkid.ro - 29 Jun 2009

    [...] the rest here: Sending emails with attachments using PHP’s mail() function Posted in PHP | Tags: a-freelance-web, a-random-hash, assignments, attachments, boundary, [...]

Afrigator