Embedding images on email (Zend Framework)

Most of the e-mail management tools (Gmail, Hotmail, Yahoo…) don’t show  images if they are coming from an external source,  like the following link:

<img src=”http://www.example.com/politician.jpg“>

The solution for this issue is to embed the images into the email. It’s  well  explained on php.net, but probably it’ll take a precious time. Fortunately for the Zend Framework developers there is a faster way.  I’ve implemented the code developed by David Nussio in the following model:

//Mail.php
<?php

class Application_Model_Mail extends Zend_Mail
{	
	public static function sendMail($subject=null,$body=null, array $recipients){
		if(empty($recipients)){
			throw new Exception('There is no email recipients defined');
		}
		$mail = new self();
		$mail->setBodyHtml($body,'UTF-8',Zend_Mime::MULTIPART_RELATED);
		$mail->setFrom('[email protected]');
		foreach($recipients as $recipient){
			$mail->addTo($recipient);
		}
		$mail->buildHtml();
		$mail->setSubject($subject);
		$mail->send();
	}
	public function buildHtml()
	{
		// Important, without this line the example don't work!
		// The images will be attached to the email but these will be not
		// showed inline
		$this->setType(Zend_Mime::MULTIPART_RELATED);

		$matches = array();
		preg_match_all("#<img.*?src=['\"]file://([^'\"]+)#i",
		$this->getBodyHtml(true),
		$matches);
		$matches = array_unique($matches[1]);

		if (count($matches ) > 0) {
			foreach ($matches as $key => $filename) {
				if (is_readable($filename)) {
					$at = $this->createAttachment(file_get_contents($filename));
					$at->type = $this->mimeByExtension($filename);
					$at->disposition = Zend_Mime::DISPOSITION_INLINE;
					$at->encoding = Zend_Mime::ENCODING_BASE64;
					$at->id = 'cid_' . md5_file($filename);
					$this->setBodyHtml(str_replace('file://' . $filename,
                                       'cid:' . $at->id,
					$this->getBodyHtml(true)),
                                       'UTF-8',
					Zend_Mime::ENCODING_8BIT);
				}
			}
		}
	}

	public function mimeByExtension($filename)
	{
		if (is_readable($filename) ) {
			$extension = pathinfo($filename, PATHINFO_EXTENSION);
			switch ($extension) {
				case 'gif':
					$type = 'image/gif';
					break;
				case 'jpg':
				case 'jpeg':
					$type = 'image/jpg';
					break;
				case 'png':
					$type = 'image/png';
					break;
				default:
					$type = 'application/octet-stream';
			}
		}

		return $type;
	}
}

For this example I’m using a mail template that is located in “application/views/scripts/mail-templates/“,  take a look at the  src attribute  of the images. All the paths  ” file://imgs/imageName” will be replaced for the embed  content of the image located on that path.

//Mail template
//example.phtml
<h1>This is a mail example</h1>
<img src="file://imgs/image1.jpg">
<img src="file://imgs/image2.jpg">

At this point we only need to call the static method sendMail with the appropiate params  (topic, body and recipients).

//Piece of code of SendMailController.php

$this->html = new Zend_View();//Create view
$this->html->setScriptPath('../application/views/scripts/mail-templates/'); 
$topic='Mail topic'; // set email subject
$body=$this->html->render('example.phtml'); //get mail template content
$recipients=array('[email protected]'); //Set list of recipients
Application_Model_Mail::sendMail($topic, $body, $recipients); 

And that’s it, I hope it helps.

Leave a Reply

Your email address will not be published. Required fields are marked *