Copy link to clipboard
Copied
I have HTML code, containing dynamic variables, stored in a database in a field named "data',. An example of raw data in that field would be:
<a href="<cfoutput>#application.siteroot#</cfoutput>/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email"><img src="<cfoutput>#application.siteroot/logo10-180.png"></a>
Within a cfc, I have code that sets this data in a <cfcontent> tag as follows:
<cfsavecontent variable="emailBody">
<cfoutput>#vData#</cfoutput>
</cfsavecontent>
However, when I tried to insert "emailBody" into an email and send it, the resulting email does not evaluate the variables in the email body and the email ends up looking like this:
What am I doing wrong?
Ah, ok. I understand your need now. You want to be able to dynamically execute the CFML which is held in the database column. Sorry, I didn't connect that dot (since your original post referred to cfsavecontent, and it used a "vdata" variable you'd not defined for us). I gather now that's the name of the variable holding the "cfml" that you obtained from the database record. Is that right?
So first, putting that inside a cfsavecontent and using cfoutput around it was not going to execute that
...Hey Charlie,
Your idea worked. Can't thank you enough. Just 4 extra lines of code got the job done.
<!--- Query database for html --->
<cfset vData = qEmailTemplate.data>
<!--- Create the temp file --->
<cfset codeQ=querynew("data","Varchar", {data=vData})>
<cfset tempfilename="savedcode#createuuid()#.cfm">
<cfset tempfile=expandpath(tempfilename)>
<cffile action="write" output="#codeQ.data#" file="#tempfile#" >
<!--- Include the tempfile in the cfsavecontent --->
<cfsavecontent variable="emailB...
Copy link to clipboard
Copied
Your code is missing some hash symbols.
<cfset Temp=QuerySetCell(q,"data","'<cfoutput>#siteRoot#</cfoutput>'",1)>
<cfset vData = q.data>
<cfdump var=#vData#>Output : '<cfoutput>/mysite/</cfoutput>'
<cfset Temp=QuerySetCell(q,"data","'<cfoutput>#siteRoot#</cfoutput>'",1)>
↓
<cfset Temp=QuerySetCell(q,"data","'<cfoutput>##siteRoot##</cfoutput>'",1)>Output: '<cfoutput>#siteRoot#</cfoutput>'
Copy link to clipboard
Copied
Hey Charlie,
Your idea worked. Can't thank you enough. Just 4 extra lines of code got the job done.
<!--- Query database for html --->
<cfset vData = qEmailTemplate.data>
<!--- Create the temp file --->
<cfset codeQ=querynew("data","Varchar", {data=vData})>
<cfset tempfilename="savedcode#createuuid()#.cfm">
<cfset tempfile=expandpath(tempfilename)>
<cffile action="write" output="#codeQ.data#" file="#tempfile#" >
<!--- Include the tempfile in the cfsavecontent --->
<cfsavecontent variable="emailBody">
<cfinclude template="#tempfilename#">
</cfsavecontent>
<!--- Send it off to Postmark API --->
<cfset resPostmark = oSystem.sendPostmarkEmail(
mailTo = qJobDetails.recipient_email,
mailFrom = application.fromEmail,
mailSubject = vSubject,
apiKey = application.postmarkAPIKey,
mailHtml = emailBody)>
Copy link to clipboard
Copied
Great to hear, and glad to have helped.
As bkbk said (and I hinted at in my original reply), this sort of dynamic code can seem compelling but comes at a cost. For now, I've helped you hitch your wagon to get back on the trail, and I do wish you well in the journey. But at some point you'll want to move up to some more reliable transportation. 🙂
Finally, thanks for marking the reply as an answer. That can really help future readers.
Copy link to clipboard
Copied
Just 4 extra lines of code got the job done.
Have you considered when and how tempfiles will be deleted?
Also, do you think there would be no performance issues if file output and compilation occur with every request?
Copy link to clipboard
Copied
Good point, @kazu98296633 . Writing to the file system can sometimes incur an even higher performance cost than reading from or writing to the database. Let alone the double whammy of reading from the database and then writing to the file system.
Sure, creating a temp file provides a solution. That helps because it gets the show moving again. But I really cannot see any justification for creating a temp file.
In fact, if you remove the file-write from your code, you will get essentially the same result. With much less cost to performance. 🙂
Here is your code again, in this new light
<!--- current page: Include containing the data --->
<cfsavecontent variable="emailBody">
<cfinclude template="/relative/path/to/tempDataFile.cfm>
</cfsavecontent>
<!--- tempDataFile.cfm: evaluate and output the data --->
<!--- Query database for html --->
<cfset vData = qEmailTemplate.data>
<cfoutput>#vData#</cfoutput>
Copy link to clipboard
Copied
Bkbk, can you clarify your last comment? Your code fragments seem to show a before and after...but both show using a tempDataFile.cfm. That doesn't exist in any other code in this thread (that I can find). Where did that come from?
You're not saying he can "just do a cfoutput in a cfsavecontent to execute the cfml coming in as a variable", as his original examples tried to do, are you? Again that doesn't work, which started the whole discussion.
Or have I missed something? Again, if there's a solution that reliably runs such "cfml in a variable" without writing to a file, I welcome seeing it.
BTW, someone may want to recommend writing to a RAM:// path, using cf's virtual file system (vfs) feature instead. I didn't propose that because a) it can be disabled and b) you can't reference that ram:// protocol in a cfinclude just like you can't provide a physical drive path. But sure, one could create a mapping (admin or app level), defining a /map alias that maps to ram://. Again, I didn't want to presume Paul or future readers would or could do that, but it's certainly an option.
Copy link to clipboard
Copied
Bkbk, ...You're not saying he can "just do a cfoutput in a cfsavecontent to execute the cfml coming in as a variable", as his original examples tried to do, are you? Again that doesn't work, which started the whole discussion.
By @Charlie Arehart
Charlie, it is not possible for me to say because there have been various versions of what is actually coming from the database. @paul_8809 can resolve this by showing us the exact, raw varchar data that is coming in from the database.
Once we know that, we will then know which string functions to use (in tempDataFile.cfm) to convert the data into suitable form.
Copy link to clipboard
Copied
Kazu, while Paul's "4 lines" didn't indicate deleting the file, my code he was responding to did. Perhaps he simply was focused on how little was needed to get to his resolution.
As for the "cost", I saw no way to avoid writing a file. (As for your alternative, while it was interesting it did not process the code that Paul's original post showed. You'd modified it to have escaped pound signs. I was just trying to offer a solution that would simply work with such code as-is.
I didn't know if there may be other facets of incoming cfml that might need special handling with your approach.. Do you? Have you had good luck with all code you've processed that way? And did you have something to also auto convert his incoming code to look like yours, or am I missing or misunderstanding something?
Since Paul accepted my approach as the solution for his need, I suspected he felt the same. Other workable solutions are welcomed, of course.
Amd while mine has the unfortunate side effect of having to write a file, the "cost" should be inconsequential in low-load scenarios. Testing or time will confirm for Paul.)
Copy link to clipboard
Copied
To clarify, in my last post,
tempDataFile.cfm
is a new CFM file, representing the query data.
Copy link to clipboard
Copied
Ok, but I thought your point was asserting there was no need to create a file. So where has that file come from in the process you're now referring to. I'm not arguing with you: I'm simply trying to take in what you're proposing as an alternative--for my sake and for other readers.
Or, again, am I missing something? That can happen especially on a phone as I am, though I try hard to avoid it.
Copy link to clipboard
Copied
In my proposal, the application does not create the file tempDataFile.cfm. In other words, the application does not write a file to the Operating System.
TempDataFile.cfm is just a template, like any other CFM within the application. It contains the query code and data.
Copy link to clipboard
Copied
Kazu, while Paul's "4 lines" didn't indicate deleting the file, my code he was responding to did. Perhaps he simply was focused on how little was needed to get to his resolution.
Charlie, I was also aware that this was a possibility.
My questions to Paul is purely out of kindness.
As for the "cost", I saw no way to avoid writing a file. (As for your alternative, while it was interesting it did not process the code that Paul's original post showed. You'd modified it to have escaped pound signs. I was just trying to offer a solution that would simply work with such code as-is.
Just to confirm, is the link incorrect?
Your code escapes pound signs as well, doesn't it? As you understand, this is necessary. I'm not quite sure why you brought this up.
Additionally, your code uses syntax other than 'cfoutput' that wasn't in Paul's original data. If that's the assumption, it's only natural that my code doesn't work, as I simply provided code to address Paul's example. This must have come from your kindness.
Amd while mine has the unfortunate side effect of having to write a file, the "cost" should be inconsequential in low-load scenarios. Testing or time will confirm for Paul.)
I think it would be better not to write to the file every time (but only write to the file once after adding or modifying).
# I'm always helped by your blog and information sharing. Thank you.
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more