how to send an HTML email with an inline attached image with PHP
I finally found the answer, which turns out to be remarkably simple. This page is what helped me figure it out, but I'll demonstrate the parts that I needed to get it done below.
First off, there's the creation of the boundary string, and the image, correctly encoded and chunked:
// Create a boundary string. It needs to be unique (not in the text) so ...
// We are going to use the sha1 algorithm to generate a 40 character string:
$sep = sha1(date('r', time()));
// Also now prepare our inline image - Also read, encode, split:
$inline = chunk_split(base64_encode(file_get_contents('figure.gif')));
In the HTML part of the email, the image is referenced like this (using the boundary string):
<img src="cid:PHP-CID-{$sep}">
Then you create another part of the email below the HTML part for the inline attachment, like this:
--PHP-related-{$sep}
Content-Type: image/gif
Content-Transfer-Encoding: base64
Content-ID: <PHP-CID-{$sep}>
{$inline}
...and that is that! Easier than implementing PHPmailer or any of the other libraries, if this is all you're doing. No doubt for more complicated task, you'll want to get one of those libraries.
Related videos on Youtube
brentonstrine
I like doing things manually. But I'm finally picking up on how incredibly useful all these new tools are.
Updated on July 09, 2022Comments
-
brentonstrine almost 2 years
I have a PHP script which sends an HTML email with an attached image. It works beauifully, however, I can't get the attachment to display in an
<img>
tag in the email body. The attached file is calledpostcard.png
and the original filename on the server is4e60348f83f2f.png
. I've tried giving the image URL as various things:cid:postcard.png
,cid:4e60348f83f2f.png
,postcard.png
, and4e60348f83f2f.png
. Nothing works.I think the key part that I'm doing wrong is here, because this makes it a separated attachment instead of an inline attachment that I can use:
Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$fname" // i.e.: "postcard.png"
I've tried changing it to use a CID but I don't really know how to do that, and this didnt' work at all:
Content-Transfer-Encoding: base64 Content-ID: <$fname> // i.e.: postcard.png
Here's the full code: (It's based on this code from a comment in the php
mail()
page.)<?php $to = "[email protected]"; $email = "[email protected]"; $name = "Namename"; $subject = "An inline image!"; $comment = "Llookout <b>Llary</b> it's <br> the <b>Ll</b>andllord!<br><img src='cid:postcard.png'><br><img src='cid:4e60348f83f2f.png'><img src='postcard.png'><br><img src='4e60348f83f2f.png'>"; $To = strip_tags($to); $TextMessage =strip_tags(nl2br($comment),"<br>"); $HTMLMessage =nl2br($comment); $FromName =strip_tags($name); $FromEmail =strip_tags($email); $Subject =strip_tags($subject); $boundary1 =rand(0,9)."-" .rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999); $boundary2 =rand(0,9)."-".rand(10000000000,9999999999)."-" .rand(10000000000,9999999999)."=:" .rand(10000,99999); $filename1 = "4e60348f83f2f.png"; //name of file on server with script $handle =fopen($filename1, 'rb'); $f_contents =fread($handle, filesize($filename1)); $attachment=chunk_split(base64_encode($f_contents)); fclose($handle); $ftype ="image/png"; $fname ="postcard.png"; //what the file will be named $attachments=''; $Headers =<<<AKAM From: $FromName <$FromEmail> Reply-To: $FromEmail MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="$boundary1" AKAM; $attachments.=<<<ATTA --$boundary1 Content-Type: $ftype; name="$fname" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="$fname" $attachment ATTA; $Body =<<<AKAM This is a multi-part message in MIME format. --$boundary1 Content-Type: multipart/alternative; boundary="$boundary2" --$boundary2 Content-Type: text/plain; charset="windows-1256" Content-Transfer-Encoding: quoted-printable $TextMessage --$boundary2 Content-Type: text/html; charset="windows-1256" Content-Transfer-Encoding: quoted-printable $HTMLMessage --$boundary2-- $attachments --$boundary1-- AKAM; // Send email $ok=mail($To, $Subject, $Body, $Headers); echo $ok?"<h1> Mail sent!</h1>":"<h1> Mail not sent!</h1>"; ?>
-
Marc B over 12 yearsUse PHPMailer or Swiftmailer. Both allow in-line attachments with absolutely NO PAIN whatsoever, unlike what you're going through to build the MIME message from scratch.
-
Parris Varney over 12 years@Marc B: I dunno, I pulled a hangnail typing once with PHPMailer, it was somewhat painful.
-
-
brentonstrine over 12 yearsThanks, however I am deleting the image from the server immediately after sending the email, so that will not work, as well as because many email clients don't allow hotlinking in emails.
-
Abby Chau Yu Hoi about 8 yearsI cannot attach according to this answer, I do like this: pastebin.com/z8LqAHCB
-
lukenofurther over 7 yearsUsing this method the image will be blocked in various email clients