Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

embedding images using cfmail...

Status
Not open for further replies.

rjuliano

MIS
Sep 30, 2003
7
US
thread232-80716 the post above the question is asked but never answered. I am developing a mail merge application using coldfusion that will be used to send out html newsletters. There will be plenty of graphics as a result. The clients can't be bothered with attaching every picture. They need a solution like Outlook provides for embedding images. Does anyone know how to do this. The images must be able to be viewed offline and not have to be attached one at a time. Please any help would be greatly appreciated. Thank you.

Rocco Juliano
Heart of Florida United Way
 
To figure out how to do this, you need to understand what Outlook (and some other email clients) are doing behind the scenes. You are, in fact, still "attaching" the images as separate files... but the body of the email message makes a special reference to the file that displays the image inline.
A lot of variables are at work, here, though. In order to make this special reference to the file, you code an HTML
Code:
<IMG>
tag into the message body. This, of course, means that the target email client must understand HTML messages. And even if it understands email messages, not all of them understand the special inline coding. So support for this solution is spotty at best.
But here's how I did it for an Intranet-based project, for which I was certain that Outlook would be used as the email client.

First, I created an array that described each of the images I wanted to use. While it looks complex, it tended to simplify things quite a bit when it came time to add additional images, etc. Each element in the array was actually a structure... the keynames of which should be fairly self-explanatory at this point:
Code:
<!--- create a new array that will hold descriptions of the images --->
<CFSET aryImageArray = ArrayNew(1)>

<!--- make the element of the array a structure --->
<CFSET aryImageArray[1] = StructNew()>
<!--- and begin to describe the image --->
<CFSET aryImageArray[1].filename = &quot;firstimage.gif&quot;>
<CFSET aryImageArray[1].contenttype = &quot;image/gif&quot;>
<CFSET aryImageArray[1].height = &quot;190&quot;>
<CFSET aryImageArray[1].width = &quot;193&quot;>
<CFSET aryImageArray[1].align = &quot;left&quot;>
<CFSET aryImageArray[1].alt = &quot;The first image&quot;>

<CFSET aryImageArray[2] = StructNew()>
<CFSET aryImageArray[2].filename = &quot;secondimage.jpg&quot;>
<CFSET aryImageArray[2].contenttype = &quot;image/jpeg&quot;>
<CFSET aryImageArray[2].height = &quot;161&quot;>
<CFSET aryImageArray[2].width = &quot;100&quot;>
<CFSET aryImageArray[2].align = &quot;right&quot;>
<CFSET aryImageArray[2].alt = &quot;The second image&quot;>

and load up the actual image data:

Code:
<!--- now we need to loop through each of our files for additional information --->
<CFLOOP from=&quot;1&quot; to=&quot;#ArrayLen(aryImageArray)#&quot; index=&quot;whichImage&quot;>
    <!--- read the file as binary data... &quot;expandpath()&quot; assumes that the image is in the same directory as the current .cfm file... adjust as needed --->
	<CFFILE action=&quot;READBINARY&quot; file=&quot;#expandpath(aryImageArray[whichImage].filename)#&quot; variable=&quot;rawBinaryImage&quot;>
	<!--- now turn that binary data into character (ASCII) data by running it through the Base64 encoder --->
	<CFSET base64data = toBase64(rawBinaryImage)>
	<!--- and insert a linefeed every 72 character (otherwise we'll overrun the mail client's maximum line length and it'll get truncated, meaning it won't be able to make sense of the image data) --->
	<CFSET lfPos = 72>
	<CFLOOP condition=&quot;lfPos LT Len(base64data)&quot;>
		<CFSET base64data = Insert(Chr(10),base64data,lfPos)>
		<CFSET lfPos = lfPos + 73>
	</CFLOOP>	
	<!--- save the character image data to our array --->
	<CFSET aryImageArray[whichImage].base64data = charImage>
	<!--- while we're at it, create a unique ID for the image. You can change this so that your ID's are of your chosing, if you wish... but this is easier if you're going to be making updates. The caveat being that CreateUUID() doesn't necessarily make a universally compatible ID for all mail clients... but it works great for Outlook --->
	<CFSET aryImageArray[whichImage].contentid = CreateUUID()>
</CFLOOP>

Now the fun part... the actual email message. What you're going to be doing is creating a &quot;multipart&quot; email. To do this, you need to use CFMAILPARAM to set up multipart boundaries for each section of the email (plain text content, HTML content, and your images). This is not always an exact science... or, maybe it is... it generally takes a try or two to get it right.
Code:
<!--- first, decide on a boundary marker. The easiest way I've found to do this is by calling CreateUUID() again. Your mileage may vary. Basically what the boundary marker says to the mail client is &quot;this is where the previous 'part' of this multipart email ends and a new one begins&quot;... so you want it to be incredibly unique... something that isn't likely to appear ordinarily in your body content of image data. --->
<CFSET sImageBoundary = CreateUUID()>

<!--- now start our actual CFMAIL tag and include a couple of CFMAILPARAM tags to set up the proper MIME header and the content description (including the boundary marker definition --->
<CFMAIL to=&quot;joe_smith@mycompany.com&quot; from=&quot;you@yourcompany.com&quot; subject=&quot;Summer Newsletter&quot;>
<cfmailparam name=&quot;mime-version&quot; value=&quot;1.0&quot;>
<cfmailparam name=&quot;content-type&quot; value=&quot;multipart/alternative; boundary=&quot;&quot;#sImageBoundary#&quot;&quot;&quot;>

--#sImageBoundary#
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

<!--- here's the plain text version that the user would get if their mail client doesn't understand HTML emails... you can put whatever content you want here. --->
This is the text version. 
Sorry... you don't get any images.
Be sure to visit our webpage for the full experience.


--#sImageBoundary#
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

<!doctype html public &quot;-//w3c//dtd html 4.0 transitional//en&quot;>
<!--- here's the HTML version --->
<html>
<body>
<p><font face=&quot;Arial&quot; size=&quot;-1&quot;>Here is the first image</font><br />
<!--- we reference the images we're going to attach with a standard IMG tag, but the source needs to be an inline reference... adding &quot;cid:&quot; at the begining of the reference, and referencing the image by it's content-id is how we do this. The IMG tags can go within any standard HTML element... like a table cell, or whatever. --->
<DIV><img SRC=&quot;cid:#aryImageArray[1].contentid#&quot; height=&quot;#aryImageArray[1].height#&quot; width=&quot;#aryImageArray[1].width#&quot; align=&quot;#aryImageArray[1].align#&quot; alt=&quot;#aryImageArray[1].alt#&quot; /></DIV></p>

<p> </p>
<p><font face=&quot;Arial&quot; size=&quot;-1&quot;>Here is the second image</font><br />
<DIV><img SRC=&quot;cid:#aryImageArray[2].contentid#&quot; height=&quot;#aryImageArray[2].height#&quot; width=&quot;#aryImageArray[2].width#&quot; align=&quot;#aryImageArray[2].align#&quot; alt=&quot;#aryImageArray[2].alt#&quot; /></DIV></p>
</body>
</html>
<!--- now we &quot;attach&quot; the images. We do this by declaring more boundaries, setting the content header for each one, and then outputting the character image data --->
<CFLOOP from=&quot;1&quot; to=&quot;#ArrayLen(aryImageArray)#&quot; index=&quot;whichImage&quot;>
--#sImageBoundary#
Content-Type: #aryImageArray[whichImage].contenttype#
Content-ID: <#aryImageArray[whichImage].contentid#>
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename=&quot;C:\WINDOWS\TEMP\#aryImageArray[whichImage].filename#&quot;

#aryImageArray[whichImage].base64data#
</CFLOOP>
--#sImageBoundary#
</CFMAIL>

The newsletter has been sent at <CFOUTPUT>#now()#</CFOUTPUT>

If you have any problems, let me know.


-Carl
 
Is there any way I can get round the <cffile here - I always want to send the same logo gif. I am using 6.1 - and would like to use "cid" refrenced image - but it's the same three everytime.

Can you help?

Mark
 
I send out over 100,000 newsletters every couple of weeks. I would never think of embedding the images. You will eventually run into a day where your message size is over 100 k and bam! you start getting stuck in spam filters.

Don't do it!

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top