[SOLVED] Dynamically adding embedded images

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

Post Reply
User avatar
Kadanis
Forum Contributor
Posts: 180
Joined: Tue Jun 20, 2006 8:55 am
Location: Dorset, UK
Contact:

[SOLVED] Dynamically adding embedded images

Post by Kadanis »

Hi

I've been playing around with Swift over the last couple of days, and I have a question about Embedding Images.

Basically, the system I want to use Swift with will allow Admins to create newsletters online (using TinyMCE or similar) and send them to members. One of the specifications is that the images used in these mails are embeded.

At the moment, I am using regex to locate all the images and to slice up the html around them. The building the message part using all the array values. However I can't seem to get it working in a loop, so it's not very flexible at the moment.

This was just for testing, and I need to streamline it so that any number of images could be used

Code: Select all

<?php

$home_dir = dirname(__FILE__);

$plain_text = <<<PLAIN
You have recieved a rich media email.  To view this on-line you need to go to the following link
{link}
Alternatively, you could change the settings on your mail client to display HTML.
PLAIN;

$email_template = <<<email
<html>
<head>
</head>
<body>
<table align="center" border="0" cellspacing="0" cellpadding="0">
<tr><td colspan="3"><img src="temp999/top.jpg" height="15" width="600" /></td></tr>
<tr>
<td><img src="temp999/left.jpg" height="160" width="342" /></td>
<td><img src="temp999/center.gif"  height="160" width="240" /></td>
<td><img src="temp999/right.jpg" height="160" width="18" /></td>
</tr>
<tr><td colspan="3"><img src="temp999/bottom.jpg" height="225" width="600" /></td></tr>
</body>
</html>
email;

/**
 * Matches all "<img src" in the HTML template
 * @return array
 * array[0] = Full <img /> tag
 * array[1] = URL without file name inside src="" property
 * array[2] = Filename from src="" proptery
 */
$image_pattern = '/<img.*?[\s]src=[\"\'](.*?)([^\/]*\.[a-zA-Z]*)[\"\'].*?>/';
preg_match_all($image_pattern, $email_template,$images);

require($home_dir . '/lib/Swift.php');
require($home_dir . '/lib/Swift/Connection/SMTP.php');

$swift =& new Swift(new Swift_Connection_SMTP('localhost'));

$email =& new Swift_Message("Test email from Swift");

$plain_part =& new Swift_Message_Part($plain_text);


/**
 * Check if the collateral exists locally
 * If not, then retireve from the app/db server
 * If it exists then replace the src in the template 
 * with the embedded image/video (if the template is
 * for an embeded / mixed client)
 * 
 */
foreach($collateral[2] as $file_index => $file_name){
	if (!is_file($home_dir . '/collateral/' . $file_name)){
		//get file
	}
	
	$full_src = $collateral[1][$file_index] . $file_name;
	
	//replace image src with identifier for html slicing
	$email_template = str_ireplace($full_src,'|~|',$email_template);	
}

//slice html
$breakdown = explode('"|~|"',$email_template);


//this is the part i'm having problems with......
$email_part =& new Swift_Message_Part(
	$breakdown[0] . 
	$email->attach(new Swift_Message_Image(new Swift_File($home_dir . '/collateral/' .$images[2][0]))) .
	$breakdown[1] . 
	$email->attach(new Swift_Message_Image(new Swift_File($home_dir . '/collateral/' .$images[2][1]))) .
	$breakdown[2] . 
	$email->attach(new Swift_Message_Image(new Swift_File($home_dir . '/collateral/' .$images[2][2]))) .
	$breakdown[3] . 
	$breakdown[4] . 
	$email->attach(new Swift_Message_Image(new Swift_File($home_dir . '/collateral/' .$images[2][3]))) .
	$breakdown[5] . 
	$email->attach(new Swift_Message_Image(new Swift_File($home_dir . '/collateral/' .$images[2][4]))) .
	$breakdown[6]
,'text/html','quoted-printable');
//end


$email->attach($email_part);


if (!$swift->send($email,'{toaddress}','{fromaddress}')){
	//handle send error
}

?>
Is there an easier way to dynamically embed the images?

As you can see I am creating the html message part and its attachments almost statically from the array. I tried looping over the arrays and building it but this seems to just cause errors.

I looked on the Wiki, but the embedded images tutorial is in the ToDo list ;)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Hi, sorry I got a bit lost reading your code and haven't had time to take a proper look since I'm in th office at work, but if you're asking how you can customize where the images point to for different emails, you can keep changing the data in the image object and the message will re-render that image (and only that image) on each send.

Code: Select all

<?php

require_once "lib/Swift.php";
require_once "lib/Swift/Connection/SMTP.php";

$swift =& new Swift(new Swift_Connection_SMTP("server"));

$message =& new Swift_Message("Some subject");

//Keep the image objects handy (doesn't matter what image you use right now)
$image1 =& new Swift_Message_Image(new Swift_File("/apth/to/any/image.jpg"));
$image2 =& new Swift_Message_Image(new Swift_File("/apth/to/any/image.jpg"));

//Embed the body with links to $image1 and $image2
$message->attach(
	new Swift_Message_Part('This is a HTML email with an image here:<br />

<img src="' . $message->attach($image1) . '" /> <br />

and another here:

<img src="' . $message->attach($image2) . '" />', "text/html"));

foreach ($whatever as $stuff)
{
	//Change where $image1 and $image2 point
	$image1->setData(new Swift_File($stuff["path_to_image_1"]));
	$image2->setData(new Swift_File($stuff["path_to_image_2"]));
	//Then send the customized message
	$swift->send($message, $to, $from);
}
User avatar
Kadanis
Forum Contributor
Posts: 180
Joined: Tue Jun 20, 2006 8:55 am
Location: Dorset, UK
Contact:

Post by Kadanis »

Yeah, sorry about the code, its kind of a brain dump as I try to work out how best to use Swift.

Acutally, what I was trying to do was be able to replace images in the HTML with embeded imgaes using a file path based on the <img src="">

The HTML is user generated so I won't know what the images are and they could be anything that the user has uploaded into their account while building the HTML template.

According to what I read on the Swift site I needed to add the HTML and the images in the style

Code: Select all

$message =& new Swift_Message("My subject");
 
$part =& new Swift_Message_Part("Here's an image <img src=\"" . $message->attach(new Swift_Message_Image(
    new Swift_File("images/foo.png"))) . "\" alt=\"\" /> embedded");
 
$message->attach($part);
I was struggling as I wanted to loop over multiple images like this

Code: Select all

$message =& new Swift_Message("My subject");
foreach($images as $image){
  //build message $part embedding image
} 

$message->attach($part);
For your info (and critique :wink: ) the way I have attempted it now is to do a string replace on the <img src="whatever"> contents so that it becomes <img=src"cid:whatever">, then used this to loop over the images.

Code: Select all

foreach($images as $image){

   $file_type = substr($image,-3);
    switch($file_type){
		case 'jpg':
		//fallthrough
		case 'jpeg':
			$type = 'image/jpeg';	
		break;
		case 'gif':
			$type = 'image/gif';
		break;
		default:
			$type = 'application/octet-stream';
		break;
	}


  $email->attach(
    new Swift_Message_EmbeddedFile(
      new Swift_File($home_dir . '/collateral/' . $image),
        $image,
        $type,
        $image,
        'base64'
      )
    );
}
it seems to be working thus far.
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

Excellent. I should note that if you get the return string "cid:dkvfbksvbis" or whatever from $msg->attach(), it will not change if ever you need to change that image for something else, you can simply change the image data it points to :) In your case however, I see what you are trying to do. The simple replacement will work fine.

NOTE: Swift_Message_Image() only needs the path to the file... it uses getimagesize() to determine the file type and uses the actual filename as the name.
User avatar
Kadanis
Forum Contributor
Posts: 180
Joined: Tue Jun 20, 2006 8:55 am
Location: Dorset, UK
Contact:

Post by Kadanis »

Thanks for the help.

I saw the Swift_Message_Image() function, but this system also embeds video. Don't ask... I'm just the programmer in this, not the designer.

As there is potential for a wmv to be in the mix I thought it best to use the Swift_Message_EmbededFile().
Post Reply