Embed image in email with PHPMailer

In a typical scenario when sending newsletters, you send to your userbase a nice HTML template with images that are loaded from the web, gaining the benefit of a small sized email message. But most email clients will not load remote images, passing the option to the user, thus making your email message look not so awesome as it should.


To overcome this problem, we can embed the images in the email. This will increase the size of your email but it will definitely look the way you intented to. With PHPMailer, you use the AddEmbeddedImage() function which simply adds the image to the class's attachments array to be written later in the e-mail's body. Then you replace the src attribute of the image tag with the id of the attached object.


$this->AddEmbeddedImage('/path/to/image.jpg', 'my-image', 'attachment', 'base64', 'image/jpeg');
// replace source with id
<img src="cid:my-image" alt="" />


This is OK if you are sending one single image, but for more images that are contained in your HTML template, you need an automatic way to do this. Here is the custom function I have written for this.


function embed_images(&$body)
{
    // get all img tags
    preg_match_all('/<img.*?>/', $body, $matches);
    if (!isset($matches[0])) return;
    // foreach tag, create the cid and embed image
    $i = 1;
    foreach ($matches[0] as $img)
    {
        // make cid
        $id = 'img'.($i++);
        // replace image web path with local path
        preg_match('/src="(.*?)"/', $body, $m);
        if (!isset($m[1])) continue;
        $arr = parse_url($m[1]);
        if (!isset($arr['host']) || !isset($arr['path']))continue;
        // add
        $this->AddEmbeddedImage('/home/username/'.$arr['host'].'/public'.$arr['path'], $id, 'attachment', 'base64', 'image/jpeg');
        $body = str_replace($img, '<img alt="" src="cid:'.$id.'" style="border: none;" />', $body);
    }
}


Possibly you will have to adjust the code to work for your project. The key point is to convert the images' web path to the local one in the filesystem. I use the domain name as the project's folder, so to convert the web path to local I use PHP's parse_url() function to grab the host name and the rest of the path to the image file. For this to work it is assumed that the web path is also absolute in the HTML template... otherwise they images would never show to the user upon reading your email message.


Code with Love.
Steve


 

 

Comments

Posted on 28.10.2014 22:52 by guest

Common sense tells me this, IF YOU have to ask how to use the above code.. You should not be attempting to use it in the first place... PHP programmers look at this and straight away know what to do...

If this is confusing you, then find a "Hello World" tutorial on PHP first and start at the basics.

Posted on 13.05.2012 10:24 by guest

Thanks a lot..this script worked for me. I had to make some changes to make it worked though. Nice script, mate..

Well, here are the things I did. I've created a file called functions.php and put this function there. Called my email body like this,
$mail->Body = embed_images(html_entity_decode($email_body), $mail);
and also made function.php file required in this send mail file.
so, I was able to initiate the same $email object from embed_image() function.
I had to change
preg_match('/src="(.*?)"/', $body, $m); line to
preg_match('/src="(.*?)"/', $img, $m);
and
if (!isset($arr['host']) || !isset($arr['path'])) {continue;} to
if (!isset($arr['host']) && !isset($arr['path'])) {continue;}
as my image paths are absolute and wasn't getting $arr['host'] set.

Posted on 03.05.2012 07:28 by guest

I still don't understand, which mail classes will you include to make this work, please give us a complete example

Posted on 25.04.2012 07:48 by guest

can you please give me a complete code for embed images in email text area with phpmailer()

Posted on 31.10.2011 23:56 by guest

Hufff, still confused..
can U please give some completely script for more images..

Posted on 08.10.2011 00:51 by guest

thanks man!!!!!

Posted on 19.03.2011 08:48 by guest

I think there is 1 problem with this script:

preg_match('/src="(.*?)"/', $body, $m);

should be

preg_match('/src="(.*?)"/', $img, $m);

Otherwise src tags that were already replaced by 'cid:...' will be replaced again.

Posted on 13.03.2011 23:33 by guest

Thanks man, just what I was looking for!