Skip to main content
Inspiring
March 6, 2025
Answered

Output variables from database in CFSAVECONTENT

  • March 6, 2025
  • 5 replies
  • 2829 views

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?

    Correct answer paul_8809

    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)>

     

    5 replies

    Charlie Arehart
    Community Expert
    Community Expert
    March 8, 2025

    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 CFML. And some people might propose that the CFML "evaluate" function could be used for this, but no: that doesn't evaluate CFML but rather only CFML expressions. It would fail on trying to render the cfoutput within the a href tag, etc. within your opening code fragment.

     

    As i said originally, many will argue against trying to support such dynamic data--partly because it's hard to execute. But it can be done. One way is to write that CFML (that vdata variable of yours) to a file and then CFINCLUDE that file (and then delete it). I offer here an example that demonstrates it, with comments to address some subtleties about it. (and of course it could be done in cfscript for those who prefer that. I stuck with tags as  Paul shows using them):

    <!--- 
    - First, simulate a query with a column that holds cfml to be executed later.
    - Because that column's content is placed here, the pound signs must be escaped.
    - That would not be needed for a real db record being read in via cfquery, etc.
    --->
    
    <cfset codeQ=querynew([{vdata:"<cfset name='bob'>This is formatted output:
    <b><cfoutput>##name##</cfoutput></b>"}])>
    <cfdump var="#codeQ#">
    
    <!--- create a temp file name and its path (need them separate, for later)--->
    
    <cfset tempfilename="savedcode#createuuid()#.cfm">
    <cfset tempfile=expandpath(tempfilename)>
    
    <!--- write the code from the query column into the temp file, using full path --->
    
    <cffile action="write" output="#codeQ.vdata#" file="#tempfile#" >
    
    <!--- include the file just written, noting that it does not allow full path--->
    
    This shows the resulting evaluated CFML/HTML to be rendered on-screen:<br>
    <cfinclude template="#tempfilename#"> 
    
    <!--- this causes the resulting evaluated CFML/HTML to be sent in an email --->
    
    <cfmail to="whoever" from="whoever" subject="whatever" server="wherever">
        <cfinclude  template="#tempfilename#"> 
    </cfmail>
    
    <!--- delete the temp file after use, after waiting a second for CF to release its hold--->
    
    <cfset sleep(1000)>
    <cffile action="delete" file="#tempfile#" >

     

    Let us know if that might help get you going. Or perhaps my comment may spark ideas from others.

    /Charlie (troubleshooter, carehart. org)
    paul_8809Author
    Inspiring
    March 8, 2025

    OK, I'll give it a shot.  Thanks for that.

    paul_8809Author
    Inspiring
    March 7, 2025

    I have done further testing.

     

    To recap, I obtain the data from a database, using the call 

    <cfset vData = qEmailTemplate.data>

    If I copy the resulting data from cflog and hardcode it before <cfsavecontent>, as below:

    <cfset vData = "<div style=""padding:1.25em 50px;text-align:center""><a href=""<cfoutput>#application.siteroot#</cfoutput>/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email""><img src=""http://aceoftrades/images/website/logo10-180.png""></a></div>">
    
    <cfsavecontent variable="emailBody">
       <cfoutput>#vData#</cfoutput>
    </cfsavecontent>

    The variables render in the email.

     

    However, if I do not hardcode it prior to <cfsavecontent>, the variables do not render in the email.

    Yet, the output from cflog dumps is exactly the same in both cases.

     

     

    BKBK
    Community Expert
    Community Expert
    March 7, 2025

    Ah. that makes sense. Thanks for clarifying.

     

    As I said, your hardcoding beforehand ensures that you get the email-body directly.

    <cfset emailBody = "<div style=""padding:1.25em 50px;text-align:center""><a href=""<cfoutput>#application.siteroot#</cfoutput>/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email""><img src=""http://aceoftrades/images/website/logo10-180.png""></a></div>">

    So there is no need for cfsavecontent.

    paul_8809Author
    Inspiring
    March 8, 2025

    Yes, if I hardcode, it all works. But that means I can't store the data in a database, then retrieve it programatically.

    i.e. I can't do:

     

    <cfset emailBody = qEmailTemplate.data>
    
    <cfset resPostmark = oPostmark.sendMail(
       mailTo = qJobDetails.recipient_email
       ,mailFrom = application.fromEmail
       ,mailSubject = vSubject
       ,apiKey = application.postmarkAPIKey
       ,mailHTML = emailBody
    )>

     

    I have to do:

     

    <cfset emailBody = "<div style=""padding:1.25em 50px;text-align:center""><a href=""<cfoutput>#application.siteroot#</cfoutput>/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email""><img src=""http://aceoftrades/images/website/logo10-180.png""></a></div>">
    
    <cfset resPostmark = oPostmark.sendMail(
       mailTo = qJobDetails.recipient_email
       ,mailFrom = application.fromEmail
       ,mailSubject = vSubject
       ,apiKey = application.postmarkAPIKey
       ,mailHTML = emailBody
    )>

     

    The whole purpose of this was the get the untidy html code out of my function and maybe have an admin page to update the html as necessary in future.

     

    BKBK
    Community Expert
    Community Expert
    March 7, 2025
    quote

    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>

     

    By @paul_8809

     

    Hi @paul_8809 , the data seems to be incorrect. The second mention of application.siteroot isn't followed by #</cfoutput>

     

    To confirm, you could test with

    <cfsavecontent variable="data">
      <cfoutput>
    <a href="#application.siteroot#/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email"><img src="#application.siteroot#/logo10-180.png"></a>
    </cfoutput>
    </cfsavecontent>
    paul_8809Author
    Inspiring
    March 7, 2025

    Well spotted, but that missing tag isn't in my code.  It occurred while pasting and cleaning up the code for this post. I can't edit my post to correct it.

    BKBK
    Community Expert
    Community Expert
    March 7, 2025

    Please look again, as there is something else. Your code uses nested <cfoutput> tags, for example, like this

     

    <cfset vData='<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>'>
    
    <cfsavecontent variable="emailBody">
      <cfoutput>#vData#</cfoutput>
    </cfsavecontent>
    

     

    Nesting cfoutput tags is not good practice. Besides, if the cfsavecontent contains nothig else, then the above code contains a repetition. That is because vData and emailBody represent the same string.

     

    I would therefore write instead

     

    <cfset vData='<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>'>
    
    <cfset emailBody = vData>

     

     

     

     

    Participating Frequently
    March 7, 2025
    <cfset application.siteroot = "https://example.com">
    <cfset vData = '<a href="<cfoutput>##application.siteroot##</cfoutput>/?utm_campaign=transactional&utm_source=emails.logo&utm_medium=email"><img src="<cfoutput>##application.siteroot##</cfoutput>/logo10-180.png"></a>'>
    <cfsavecontent variable="emailBody">
      <cfoutput>#vData.reReplace("<cfoutput>(##[^##]+##)</cfoutput>", function(obj){return Evaluate(obj.match[2]);}, "all")#</cfoutput>
    </cfsavecontent>
    <cfoutput>#emailBody#</cfoutput>
    paul_8809Author
    Inspiring
    March 7, 2025

    Thanks for replying! This throws an error, as follows:

     

    Participating Frequently
    March 7, 2025

    I ran the test in CF2021, CF2023 and CF2025.

    https://cffiddle.org/

    It doesn't work well in my CF2018 environment.

    Charlie Arehart
    Community Expert
    Community Expert
    March 6, 2025

    Update to my original comment, for future readers of this thread: skip to my new reply thread here a couple days later, where I came to better understand the problem. (I leave the rest here and the back and forth which follows, for the sake of context.) Or of course see other reply threads here, from others. I just am referring to the replies between Paul and me the first day about this first reply of mine.

     

    Focus first on outputting the value right after the cfsavecontent. Is it correct then? If so, it would not become incorrect simply because the same variable result was put in a cfmail. 

     

    (And if you'd contend that you "can't output the variable there", log it instead with cflog.) 

     

    Some may propose also/instead that you put a cfoutput within the cfmail, but you have it already in the cfsavecontent. That's why I assert that if that same variable is passed to the cfmail, the cfml should already be evaluated. But if you try it and it works, something else was at play in your code. 

     

    Finally, some would want to discourage the approach of storing cfml code in a db, to then run dynamically. I'll leave that debate for them to contend with you. (That said, nothing in your code or the remaining discussion conveys where the db involvement is. It may or may not be significant.) 

     

    PS I'll change your title, as you said cfcontent when your clearly meant cfsavecontent. 

    /Charlie (troubleshooter, carehart. org)
    paul_8809Author
    Inspiring
    March 6, 2025

    Hi Charlie, I tried but placing the cfoutput below the cfsavecontent did not work in displaying the variables. I'll keep trying

     

    Charlie Arehart
    Community Expert
    Community Expert
    March 6, 2025

    I didn't suggest that. Please re-read carefully. And I offered a couple of suggestions. 

    /Charlie (troubleshooter, carehart. org)