Image embedded in email shows like a negative of the original image

MaxwellTurner
MaxwellTurner used Ask the Experts™
on
ColdFusion 9

I am trying to embed a signature image into an email.  The image is created:

<cfoutput><cfsavecontent variable="content">#TicketSignature#</cfsavecontent></cfoutput>
<cfset Signature = ImageReadBase64(content) />
<cfimage name="thisSignature" source="#Signature#" action="read" >

When I "WritetoBrowser" the image appears fine.  All good so far.

In my Cfmail tag I use:

<cfmailparam file="signature.png" contentid="signature" content="#thisSignature#" disposition="inline" type="image/png" />
and
<img src="cid:signature"> to show the image.

My problem:  For some reason the image in the email is viewed as a negative image ... black background and light blue signature.  Somehow, the cfmailparam tag is converting the image.  Why???  I have tried everything I can think of, but nothing will change it back to white background and black signature.

Any thoughts would be very helpful.

Max
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2015

Commented:
IMO, the code isn't doing anything wrong - it's probably just a bug.  There are a number of image related bugs, some fixed in later versions.
https://stackoverflow.com/a/37769705/8895292

If I had to guess, cfmailparam is picking the wrong image type and/or color profile, which results in reversed colors. Hate to say it, but you may have to try the workaround in the thread above. Namely, save the image to a file and use the "file" with cfmailparam. Don't forget to use remove="yes" so it gets cleaned up.  (Yes, I realize you were probably trying to avoid more files, but .. it's the only workaround I can think of).

Author

Commented:
Hi agx_,  this is a problem you helped me with a while back.  I was in fact doing what you suggest ... save the image to file, then remove it using REMOVE in cfmailparam.  I used a test email address and it worked perfectly!

I encountered a problem however:  the application actually uses a list of email addresses - from 3 to 5 addresses.  I decided to CFLOOP through the addresses and use a counter to determine when to remove the address:

<cfset emailcounter = 1 />
<cfloop list="#emailto# index="e">
         <cfif emailcounter eq listlen(emailto)>
             <cfset removeimage = "yes">
       <cfelse>
             <cfset removeimage = "no">
       </cfif>
       <cfmail to="#e#" >
               ... email body ...
               <cfmailparam file="#ExpandPath('./tmpSigImage.png')#" contentid="signature" disposition="inline" remove="#removeimage#" />
       </cfmail>
       <cfset emailcounter = emailcounter + 1 />
</cfloop>

With a list of 4 email addresses, only one or two emails would send.  After studying my logs, I finally determined that it was the first one or two emails that was being moved to my Mail\Undelivr folder saying it could not find the image, making me believe that the image was not being created fast enough.  This is why I decided to try using a variable.

Using the variable, all 4 emails send, but now I have the problem of a negative image!!  Doh!  Just can't win.

I have no problem creating another file ... Do you know of a trick ... maybe a small pause/timer placed between creating the image and the cfmail code?

Thanks,

Max

Author

Commented:
btw, I also tried creating the image to file, then did a <cflocation> back to the same page ... hoping that would provide enough time for the image to be created, but it did not work either ... only 2 of 4 email would sent.

Strangley, if I simply change REMOVE=NO in the cfmailparam, all 4 email send fine.  I figured, akay, I'll just remove the file using directly after the cfloop:

<cfif FileExists("#expandPath('.')#\tmpSigImage.png")>
       <cffile action="delete" file="#expandPath('.')#\tmpSigImage.png" />
 </cfif>

When I tried this, none of the emails sent ... logs telling me the image was not found.  Not sure what is happening here.  Is it deleting the image too soon now?

Max
Introduction to R

R is considered the predominant language for data scientist and statisticians. Learn how to use R for your own data science projects.

Most Valuable Expert 2015
Commented:
Yes, unfortunately it sounds like it is removing the images too soon. Since the mail is spooled, it is hard to reliably know the order the messages are sent or when it is 100% safe to delete the image, since it is used by more than one email.

Unfortunately, the only workarounds I can think of are kludgey. Like creating 1 file per address. Would work, but is not ideal.

When you saved the image to a file, what file type did you use: png or jpg?
Most Valuable Expert 2015

Commented:
BTW, you tried everything else I would have tried too!

> I figured, akay, I'll just remove the file using directly after the cfloop:


You'd think that would work, but due to spooling, it doesn't. Spooling means they aren't sent right away, or maybe not even in the order you created them. So that would only work if you disable spooling - which is not ideal.

Author

Commented:
Hmmm, I think I was fooled into thinking it was not creating the image fast enough because it was consistently the first 2 on the LIST that did not send, however what you say makes sense, especially if I change REMOVE to NO and all 4 send.

I watched my SPOOL folder as I clicked the link and counted in my head how long the emails sat there ... turns out about 7 seconds.  I added this little bit of code, and viola, all 4 sent!  However, not a great solution as it takes 7 seconds for the next 'confirmation' page to load ... I was hoping the page would load and I could display a "please wait" gif for 7 seconds.

<cfset wait_time = 7>
<cfset Future = Second(Now()) + wait_time>
<cfloop index="Z" from="1" to="1000000000000" step="+1">
      <cfif Second(Now()) GTE Future>
              <cfbreak>
        </cfif>
</cfloop>
<cfif FileExists("#expandPath('.')#\tmpSigImage.png")>
          <cffile action="delete" file="#expandPath('.')#\tmpSigImage.png" />
 </cfif>

So still looking for a way to clean this image up.  This is actually a several step wizard, and I could do the FILEEXISTS clean-up at the beginning, but would much rather get rid of the signature after ...

I read somewhere that I could delete the image once a Session expires .... I am in fact using Session variables for this process.  How can I tell the session to delete the image when it expires ... it expires when I close the browser ... correct?

Max
Most Valuable Expert 2015

Commented:
It sounded to me like they weren't sending because the file was deleted before the mails were sent ;-)

Session handling would work (...mostly, more about that in a sec). Technically the session doesn't expire when the browser is closed. It still lives on, on the server until the time elapsed since the user's last activity exceeds the server timeout.  Example, say the server session timeout is 20 minutes, and the user doesn't request any pages for 22 minutes - because they went for coffee - after 20 minutes, the session expires on the server.

Since spooled mails are sent asynchronously, it becomes a bit of a guessing game.  You could add some code the OnSessionEnd method in your Application.cfc, to delete the file. BUT .... there's still a small, outside chance the image will be in use at that time. In which case, the email wouldn't send.  Sadly the only sure-fire to ensure the file is deleted is to create 1 file for each email, and use remove=yes to let CF handle. Either that or don't use remove=yes and instead create a scheduled job, to clean up image files periodically.

None of them great options, but .. the only reliable ones if you want to be certain an email doesn't fail because of a missing image.

Author

Commented:
I put this outside of the cfloop:

<cfoutput><cfsavecontent variable="content">#TicketSignature#</cfsavecontent></cfoutput>
<cfset Signature = ImageReadBase64(content) />

and this inside the cfmail (and inside the cfloop):

<cfimage source="#Signature#" destination="tmpSigImage.png" action="write" overwrite="true">
<cfmailparam file="#ExpandPath('./tmpSigImage.png')#" contentid="signature" disposition="inline" remove="yes" />

and only get 1 of 4 emails successfully, so even creating a new image for each email is too fast for the spooling emails .... that is what you meant right?

This application is a multi-step wizard (a support ticket system)  ... I think my only option left is to do my fileexists & delete check on step ONE (create a new ticket) and keep REMOVE=NO, instead of deleting the image on the final step.  Maybe a scheduled job at the end of that day too.  Hopefully 2 separate users don't time it 'just right' where someone creating a new ticket deletes the image that someone just finishing a ticket has just created ... but quite unlikely as there will only be 15 or so users that will be using this application.  I'll buy a lottery ticket if that happens!  lol

Max
Most Valuable Expert 2015

Commented:
Oh...Sorry, I left out an important detail about the separate files. They must have unique file names. Otherwise you still have the same problem. Threads deleting the image before the emails that use it are sent.

Try using something like #createUUID()#.png. since they're embedded, the file name doesn't matter anyway.
Most Valuable Expert 2015

Commented:
Obviously with a full path too ;-)

Author

Commented:
Well shucks, I'm feeling a little silly again.  lol  Of course! ... unique image names!  I wasn't thinking this through properly.  I already had a counter so I just added #emailcounter# to the image name and 'ta da'! it worked.  Sad thing is this is one of the first things I tried early on even before I switched to a variable image and posted here.  I can't believe I didn't think of unique image names at the time ... would have saved much head scratching. lol  Oh well, the hardest lessons learned tend to stick best ...

Thanks again _agx_, now I can finally put this behind me and go on Christmas break without this hanging over my head!

Happy Holidays!

Author

Commented:
After re-reading I see you mentioned this multiple times earlier ... sorry it took me a bit to clue in ... when you mentioned unique names I paused, then gave my self a face palm (long sigh).  This is a great solution as far as I'm concerned.

Max
Most Valuable Expert 2015

Commented:
>Oh well, the hardest lessons learned tend to stick best ...

Don't I know it! Glad it is all resolved. Though really, you shouldn't have to do all this if cfimage/cfmailparam didn't muck up the inages in the first place.

Ah well..  all is well, that ends well. Have a Merry Christmas!
Most Valuable Expert 2015

Commented:
>  I already had a counter so I just added #emailcounter# to the image name and 'ta da'! it worked.  

One thing about that. I'd still recommend using createUUID instead. Reason being  a counter number isn't *globally* unique. If two requests hit that .cfm page at the same time, they'll be using the same file names and overwriting and deleting each other's images.

In theory, CreateUUID is globally unique. So the chances of two threads generating the same file name, at the same time, are reallly, really small. So it is much safer.

Author

Commented:
Thanks _agx_,

I was away for the holidays for a bit ... I can see the wisdom of what you suggest and will incorporate it.

Thanks again,

Max

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial