Skip to main content
Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.

Adobe ColdFusion 2018 Compatible Version Of My ColdFusion Custom Tag DSL For HTML Emails

By Ben Nadel on
Tags: ColdFusion

Over the past couple of months, I've been working on a ColdFusion custom tag DSL (Domain Specific Language) for HTML emails. It's been a thrilling adventure; and, it's been tremendously satisfying to see this approach being applied for great good at InVision. That said, InVision runs on Lucee CFML and my personal blog (this blog) runs on Adobe ColdFusion 2018. And, unfortunately, there's enough incompatibility between the two runtimes such that I can't easily use the same code. As such, I've created a new repository for an Adobe ColdFusion compatible version.

View this code in my ColdFusion Custom Tag Emails (ACF) project on GitHub.

The main compatibility issues are:

Most of these issues could be smoothed-over such that a single code-base could be used for both the Lucee CFML and Adobe ColdFusion runtimes. But, we would lose efficiencies, especially with the cacheWithin compile issues. So, for the time being, these will be in different proof-of-concept repositories.

Just as a reminder, this is what it looks like to author an email using my ColdFusion custom tag DSL:

<!--- Import custom tag libraries. --->
<cfimport prefix="core" taglib="./core/" />
<cfimport prefix="html" taglib="./core/html/" />
<cfimport prefix="imageGrid" taglib="./customized/image-grid/" />
<cfimport prefix="customized" taglib="./customized/" />

<!--- // ------------------------------------------------------------------------- // --->
<!--- // ------------------------------------------------------------------------- // --->

<core:Email
	subject="Ben Nadel has met some amazing people!"
	teaser="See them for yourself!">
	<core:Body>

		<html:h1>
			<core:NoWrapText>Ben Nadel</core:NoWrapText> has met some truly
			<html:a href="www.bennadel.com/people" decoration="false">
				amazing people
			</html:a>
		</html:h1>

		<html:p>
			Good morning my beautiful, beautiful friends!
		</html:p>

		<html:p>
			In the midst of the <html:em>stress</html:em> of this global pandemic, it's
			important to <html:strong>remain thankful</html:strong> for all the good
			people that we have in our lives. And, while we can't see our people as much
			as we might like, we can let the memory of them keep us warm.
		</html:p>

		<html:p>
			Here are some of the great people that I've met:
		</html:p>

		<imageGrid:List>
			<imageGrid:Image
				title="Sara Dunnack"
				src="https://bennadel-cdn.com/images/header/photos/sara_dunnack_3.jpg"
			/>
			<imageGrid:Image
				title="Sara Dunnack"
				src="https://bennadel-cdn.com/images/header/photos/sara_dunnack_3.jpg"
			/>
			<imageGrid:Image
				title="Sara Dunnack"
				src="https://bennadel-cdn.com/images/header/photos/sara_dunnack_3.jpg"
			/>
			<imageGrid:Image
				title="Sara Dunnack"
				src="https://bennadel-cdn.com/images/header/photos/sara_dunnack_3.jpg"
			/>
		</imageGrid:List>

		<html:p>
			Oh the memories! To see more wonderful people, check out my People section.
		</html:p>

		<customized:CallToAction href="www.bennadel.com/people" margins="normal">
			See More People
		</customized:CallToAction>

		<html:hr margins="double" />

		<html:p>
			The following is just a bunch of random style stuff to experiment with and
			to see how this all renders in email clients.
		</html:p>

		<html:h1>
			Favorite movies
		</html:h1>

		<html:p>
			There are a lot of great movies out there. I like movies across all genres;
			from action, to rom-com, to sci-fi, to drama &mdash; they all have their
			place. But, I have to admit that my <html:em>favorite genres</html:em> are
			definitely <html:strong>Action</html:strong> and
			<html:strong>Romantic Comedies</html:strong>
		</html:p>

		<html:h2>
			Best Meg Ryan movies
		</html:h2>

		<html:p>
			And ... when it comes to Romantic Comedies, there's no one better than Meg
			Ryan. For Years, Ryan was America's sweetheart, delighting audiences and 
			making us swoon in such films as:
		</html:p>

		<html:ul>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0098635/">
					When Harry Met Sally
				</html:a>
				&mdash;
				<html:mark>this is my favorite!</html:mark>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0128853/">
					You've Got Mail
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0108160/">
					Sleepless in Seattle
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0113117/">
					French Kiss
				</html:a>
			</html:li>
		</html:ul>

		<html:h2>
			Great movie quotes
		</html:h2>

		<html:p>
			One of the great features of a <html:em>feature</html:em> film (see what I
			did there) is that they leave you with dynamite quotes that really make you
			think. One of the highly quotable scenes that I've been thinking about a lot
			lately is from Blade Runner.
		</html:p>

		<html:h3>
			Blade Runner (1982)
		</html:h3>

		<html:p>
			In the last scene of this sci-fi classic, Rutger Hauer contemplates existence
			in the final moments of this life:
		</html:p>

		<html:blockquote>
			<html:p margins="none">
				I've seen things you people wouldn't believe. Attack ships on fire off
				the shoulder of Orion. I watched C-beams glitter in the dark near the
				Tannhauser Gate. All those moments will be lost in time, like tears
				in rain.
			</html:p>
		</html:blockquote>

		<html:p>
			Now, in the <html:em>Director's cut</html:em> of the film, that the end of
			it. But, in the general release cut, Harris Ford follow-up with some
			narration that&mdash;in my opinion&mdash; adds a lot of needed color:
		</html:p>

		<html:blockquote>
			<html:p margins="none">
				I don't know why he saved my life. Maybe in those last moments he loved
				life more than he ever had before. Not just his life - anybody's life;
				my life. All he'd wanted were the same answers the rest of us want.
				Where did I come from? Where am I going? How long have I got? All I could
				do was sit there and watch him die.
			</html:p>
		</html:blockquote>

		<html:h2>
			Top 5 Arnold Schwarzenegger movies
		</html:h2>

		<html:p>
			Obviously, no discussion about movies could ever be considered complete if it
			didn't pay homage to the <html:em>master blaster</html:em> himself &mdash;
			<html:mark>Arnold Schwarzenegger</html:mark>. To make sure we cover all of
			our bases, here are my Top 5:
		</html:p>

		<html:ol>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0103064/">
					Terminator 2
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0111503/">
					True Lies
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0100802/">
					Total Recall
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0099938/">
					Kindergarten Copy
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0096320/">
					Twins
				</html:a>
			</html:li>
			<html:li>
				<html:a href="https://www.imdb.com/title/tt0093773/">
					Predator
				</html:a>
				&mdash;
				<html:mark>Because "5" isn't enough!</html:mark>
			</html:li>
		</html:ol>

	</core:Body>
	<core:TrackingPixel src="https://img.spacergif.org/v1/spacer.gif" />
</core:Email>

As you can see, we're using ColdFusion custom tags to implement basic HTML elements. These custom tags then handle all of the CSS property inlining into style attributes.



Reader Comments

@Brad,

Good question. I just use CommandBox via cfengine=adobe@2018. I guess I just assumed that would be using whatever the latest version was. But, maybe I need to update the cached artifacts or use a patch number in the engine call. As you know, I only CommandBox at a 2nd grade level :D

Reply to this Comment

The command you showed should start the latest update of 2018 which supports lambdas. Are they not working for you on the server you started? No need to do anything with artifacts, etc. Each version of the engine is a new version of the artifact, so CommandBox will download it as necessary.

Reply to this Comment

@Brad,

Hmmmm, Ok, so when I went to test it out this morning, it looked like CommandBox actually installed something new:

CommandBox> start cfengine=adobe@2018
 - | Starting Server
   |------------------------------
   | Contacting ForgeBox to determine the latest & greatest version of [adobe 2018]...  
   | Use an exact 'cfengine' version to skip this check.
   | OK, [adobe 2018.0.11+326016] it is!
   | Exploding WAR/zip archive...
   |------------------------------
   | √ | Installing package [forgebox:adobe@2018]

And now, when I try the same code that was causing compilation errors before, it works :man-shrug:. No idea why this wasn't working earlier. I wonder it's because I had a server.json file that had "cfengine":"adobe@2018"? Maybe that caches harder somehow? For this test (above), I just did started the server directly from the CLI rather than from the directory that has the server.json file.

Reply to this Comment

@Brad,

Also, totally random aside, I never a problem stopping a Lucee server. But, when I go to stop an ACF server, I've been getting this lately:

CommandBox> stop
Stopping lucee...
ERROR
Error invoking external processCannot run program "/Library/Internet": error=2, No such file or directory
Reply to this Comment

@Ben,

That's a new one. I did fix an issue in the latest version of CommandBox that output any messages from the console that occurred when stopping a server. That message was likely always there but not showing up. I don't recognize any of it though. Perhaps it's specific to a Mac. Can you ping me when you get a chance on Slack so I can take a look at it? I think I also converted some old cfexecute code to Java's Process builder inside the stop command but it's working on Windows so there may just be a pathing issue on Mac.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Blog
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.