Okay, this is it; Howto: Send HTML formatted emails with PHP with image attachments that work with Outlook and Gmail

I have to start off by saying that Gmail is excellent and has worked correctly through each stage of my testing, Outlook was the only mail reader that didn’t work correctly in my testing.


Perhaps I should actually start off by saying that; yes, you can use images hosted on your web server in your HTML body of your message. Since evil-doers do this to track valid email addresses though, mail readers block your images so the user isn’t exposed and they have to click on something to see your images. The solution to get your pretty message to your viewers is to send your message with the image as an inline attachment, that way there’s no way you can find out who read your message by looking through your server logs.


If you want to send a styled message that works with all of the mail readers out there, it’s all in the way you code it. First of all, if you’re not sending out a text and an HTML format, you may get nabbed by some spam scanners. So this is how my original email looked.

To: “You” <you@your.address.com>

From: “Me” <me@my.address.com>

MIME-Version: 1.0

Content-Type: multipart/alternative; boundary=”something”


–something

Content-type: text/plain; charset=iso-8859-1


my message here


–something

Content-type: text/html; charset=iso-8859-1


<HTML>my html message here<BR><IMG SRC=”cid:myimage”><HTML>


–something

Content-type: image/gif; name=”myimage.gif”

Content-Transfer-Encoding: base64

Content-ID: <myimage>

Content-Description: myimage.gif

Content-Location: myimage.gif


[BASE64 ENCODED FILE HERE]


–something–

That worked great on Gmail and other sane mail readers because it could find everything it needed, but it just showed a broken image when you opened that message in Outlook. So after some trial and error, this is what the message had to look like:

To: “You” <you@your.address.com>

From: “Me” <me@my.address.com>

MIME-Version: 1.0

Content-Type: multipart/alternative; boundary=”something”


–something

Content-type: multipart/alternative; boundary=”stupidoutlook”


–stupidoutlook

Content-type: text/plain; charset=iso-8859-1


my message here


–stupidoutlook

Content-type: text/html; charset=iso-8859-1


<HTML>my html message here<BR><IMG SRC=”cid:myimage”><HTML>


–stupidoutlook–


–something

Content-type: image/gif; name=”myimage.gif”

Content-Transfer-Encoding: base64

Content-ID: <myimage>

Content-Description: myimage.gif

Content-Location: myimage.gif


[BASE64 ENCODED FILE HERE]


–something–

That’s all good. So now, let’s make it in PHP quickly and easily…

<?
    $from 
'"Me" <me@my.address.com>';
    
$to '"You" <you@your.address.com>';
    
$subject 'My awesome message';
    
$message  '<HTML>' "n";
    
$message .= 'my message is totally awesome.<P>' "n";
    
$message .= '<B>Seriously.  it's wicked.</B><P>' "n";
    
$message .= '<IMG SRC="cid:myimagecontentidname">' "n";
    
$message .= '</HTML>';

    $images = array(
        
'path/to/myimage.gif' => 'myimagecontentidname',
    
);

    if (sendmessage($from$to$message$images)) {
        echo 
"message sent";
    }

    function sendmessage ($from$to$message$images = array());
        
$boundary md5(uniqid(time()));

        $headers  'MIME-Version: 1.0' "n";
        
$headers .= 'Content-Type: multipart/alternative; boundary="' $boundary '"' "n";
        
$headers .= $from "n";

        $body  '--' $boundary "n";
        
$body .= 'Content-type: multipart/alternative; boundary="' $boundary '.textparts"' "nn";

        $body .= '--' $boundary ".textpartsn";
        
$body .= 'Content-type: text/plain; charset=iso-8859-1' "nn";

        $body .= striptags($message) . "nn";

        $body .= '--' $boundary ".textpartsn";
        
$body .= 'Content-type: text/html; charset=iso-8859-1' "nn";
        
        
$body .= $message "nn";

        $body .= '--' $boundary '.textparts--' "nn";

        foreach ($images AS $imagefile => $cid) {
            
$body .= '--' $boundary "n";
            
$body .= 'Content-Type: image:' substr($imagefilestrrpos($imagefile".") + 1) . "n";
            
$body .= 'Content-Transfer-Encoding: base64' "n";
            
$body .= 'Content-ID: ' $cid "n";
            
$body .= 'Content-Description: ' substr($imagefilestrrpos($imagefile"/") + 1) . "n";
            
$body .= 'Content-Location: ' substr($imagefilestrrpos($imagefile"/") + 1) . "nn";

            $body .= chunk_split(base64_encode(file_get_contents($imagefile))) . "nn";
        }
        
        
$body .= '--' $boundary "--n";

        return(mail($to$subject$body$headers));
    }
?>


One last thing that you should note when sending out mail to a wide variety of clients, mail readers like Gmail ignore <BODY> tags and <STYLE> tags, for those colours, properties to be defined, you have to use the STYLE property on each item you want styled a certain way other than the default. (ie: <FONT STYLE=”font-family: Tahoma, Arial; font-size: 8pt;>do it on one wheel, ride a unicycle</FONT>) The best practice is to test, test and test again. On average I send out about 10-20 test messages to myself before I get it just right everywhere.

Author: Ian

Share This Post On

Submit a Comment

Your email address will not be published.