PHP send an email with image attachment
Asked Answered
N

4

6

I'm trying to create a script that will send an image uploaded from an iphone app I'm developing to me in an email.

I've been able to get the script to send me an email with an attachment. However, the attachment is always 0kb.

Here is my code:

// Standard email info


$to = '[email protected]'; 
 $subject = 'Email with an image attached'; 

 // This variable will be used when declaring the "boundaries"
 // for the different sections of the email
 $boundary = md5(date('r', time()));

 //Initial Headers 
 $headers = "MIME-Version: 1.0\r\n"; // <- the "\r\n" indicate a carriage return and newline, respectively
 $headers .= "From: <[email protected]>\r\n";
 $headers .= "Content-Type: multipart/mixed; boundary=" . $boundary . "\r\n"; // <- This is 
 // saying the there will be more than one (a "mix") of Content Types in this email.
 // The "boundary" value will indicate when each content type will start

  //First Content Type
 $message = "\r\n\r\n--" . $boundary . "\r\n"; // <- This indicates that I'm going to start
 // declaring headers specific to this section of the email. 
 // MAKE SURE there's only ONE(1) "\r\n" between the above boundry and the first header below (Content-Type)
 $message .= "Content-type: text/plain; charset=\"iso-8859-1\"\r\n"; // <- Here I'm saying this content should be plain text
 $message .= "Content-Transfer-Encoding: 7bit\r\n\r\n";

 // Body of the email for the headers I just declared 
 $message .= "Someone filled out the form. See their info below:\r\n";
 $message .= "Name:";

//Second Content Type
 $message .= "\r\n\r\n--" . $boundary . "\r\n"; // <- This idicates that I'm going to start 
 // declaring some more headers for the content below
 // MAKE SURE there's only ONE(1) "\r\n" between the above boundry and the first header below (Content-Type)
 $message .= "Content-type: image/jpeg\r\n"; // <- Here I'm saying that this Content Type is for a JPEG image
 $message .= "Content-Transfer-Encoding: base64\r\n"; // <- this is saying that this section's content will be base64 Encoded
 $message .= "Content-Disposition: attachment; filename=\"Image.jpg\"\r\n"; // <- This is saying the content below should be an attachment and gives it a file name

 // The base64_encode below is necessary because this is a file. 
 $message .= base64_encode(file_get_contents($_FILES["userfile"]["name"])); 

 $message .= "\r\n\r\n--" . $boundary . "--"; // <- This indicates the end of the boundries. Notice the additional "--" after the boundry's value.

 // Send the email using "mail()".
 // Adding the "$mail_sent = " before "mail()" will store TRUE in $mail_sent if the email is sent successfully
 // Adding the "@" sign before "mail()" will disable error display so users
 // won't see the actual error info if it fails, just "Mail failed".
 $mail_sent = @mail($to, $subject, $message, $headers); 

 //Check to see if the email was sent successfully ($mail_sent = true).
 //If so, display "Mail Sent" to the screen, else display "Mail Failed".
 echo $mail_sent ? "Mail sent" : "Mail failed"; 

Everything works fine except the attachment is 0kb.

Any help is appreciated.

Thanks.

Neutron answered 28/6, 2013 at 15:51 Comment(1)
Don't build your own mime emails. Use PHPMailer or Swiftmailer. They both make it trivial and reduce your code to just a few lines.Dimetric
S
11
        // to, from, subject, message body, attachment filename, etc.
        $to = "[email protected]";
        $from = "[email protected]";
        $subject = "subject";
        $message = "this is the message body";
        $filename = "/home/user/file.jpeg";
        $fname = "file.jpeg";

        $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            
            $file = fopen($filename,"rb");
            $data = fread($file,filesize($filename));
            fclose($file);
            $data = chunk_split(base64_encode($data));
            $message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"".$fname."\"\n" . 
            "Content-Disposition: attachment;\n" . " filename=\"$fname\"\n" . 
            "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
            $message .= "--{$mime_boundary}--\n";


        // send
        //print $message;

        $ok = @mail($to, $subject, $message, $headers, "-f " . $from);          
Sunward answered 28/6, 2013 at 18:55 Comment(2)
How to attach multiple image files ? @SunwardFacile
Probably using uniqid() for boundary will be a better wayDeboer
A
3

While there are canned functions for this, what a fantastic exercise for a junior programmer!

Very well written mti2935. It would do folks good to actually read and not just cut-and-paste. If you're sending email with php, you should understand these fundamental concepts.

Probably some oversights from masking your real code:

Line 23 should be:

$data = fread($file,filesize($filename));

That is, $fname should be $filename.

Line 26 should be:

$message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"".$fname."\"\n" .

Neither $x nor $files[$x] are defined.

@Thomas Spade: I'd like to remind that you should always sanitize input (email address).

Aristate answered 24/11, 2013 at 7:54 Comment(0)
S
0

And the closing mime boundary should end in --, so line 29 should read:

$message .= "--{$mime_boundary}--\n";
Spit answered 24/11, 2014 at 15:39 Comment(0)
H
0
<?php

$url = "https://c.xkcd.com/random/comic/";
$ch  = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
// Must be set to true so that PHP follows any "Location:" header.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// $a will contain all headers.
$a = curl_exec($ch);
// This is what you need, it will return you the last effective URL.
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);

$str  = file_get_contents($url.'info.0.json');
$json = json_decode($str, true);

// Get file info.
$imageTitle = $json['title'];

// Image url.
$imageUrl = $json['img'];

// Image alt text.
$imageAlt = $json['alt'];

// Image file.
$imageFile = file_get_contents($imageUrl);

$tokens = explode('/', $imageUrl);

// File name.
$fileName = $tokens[(count($tokens) - 1)];

// File extension.
$ext = explode(".", $fileName);

// File type.
$fileType = $ext[1];

// File size.
$header = get_headers($imageUrl, true);

$fileSize = $header['Content-Length'];




$to      = '[email protected]';
$subject = "Enjoy reading today's most interesting XKCD comics";
$message = '
<html>
<head>
<title>Your email '.$to.' is listed in our XKCD comics subscribers.</title>
</head>
<body> 
    <h1>'.$imageTitle.'</h1>
    <img src='.$imageUrl.' alt='.$imageAlt.'>
</body>
</html>';

// File.
$content = chunk_split(base64_encode($imageFile));

// A random hash will be necessary to send mixed content.
$semiRand     = md5(time());
$mimeBoundary = '==Multipart_Boundary_x{$semiRand}x';

// Carriage return type (RFC).
$eol = "\r\n";

$headers  = 'Reply-To: Name <[email protected]>'.$eol;
$headers .= 'Return-Path: Name <[email protected]>'.$eol;
$headers .= 'From: Name <[email protected]>'.$eol;
$headers .= 'Organization: Hostinger'.$eol;
$headers  = 'MIME-Version: 1.0'.$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"{$mimeBoundary}\"".$eol;
$headers .= 'Content-Transfer-Encoding: 7bit'.$eol;
$headers .= 'X-Priority: 3'.$eol;
$headers .= 'X-Mailer: PHP'.phpversion().$eol;

// Message.
$body  = '--'.$mimeBoundary.$eol;
$body .= "Content-Type: text/html; charset=\"UTF-8\"".$eol;
$body .= 'Content-Transfer-Encoding: 7bit'.$eol;
$body .= $message.$eol;

// Attachment.
$body .= '--'.$mimeBoundary.$eol;
$body .= "Content-Type:{$fileType}; name=\"{$fileName}\"".$eol;
$body .= 'Content-Transfer-Encoding: base64'.$eol;
$body .= "Content-disposition: attachment; filename=\"{$fileName}\"".$eol;
$body .= 'X-Attachment-Id: '.rand(1000, 99999).$eol;
$body .= $content.$eol;
$body .= '--'.$mimeBoundary.'--';

$success = mail($to, $subject, $body, $headers);

if ($success === false) {
    echo '<h3>Failure</h3>';
    echo '<p>Failed to send email to '.$to.'</p>';
} else {
    echo '<p>Your email has been sent to '.$to.' successfully.</p>';
}
Hued answered 1/7, 2021 at 4:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.