Ask Ben: Creating A PDF And Attaching It To An Email Using ColdFusion

Posted September 4, 2009 at 5:39 PM

Tags: ColdFusion, Ask Ben

Do you know how to save a cfdocument and then attach it to a cfmail all on submit?

This is one of the many tasks that ColdFusion happens to make very easy. We can use the CFDocument tag to generate the PDF and store it in memory; then, we can use the CFMail tag and the CFMailParam tag to attach our generated PDF to the outgoing email. With the release of ColdFusion 8, we were given the ability to attach variable data directly to emails using the CFMailParam Content attribute without going to the file system; this means that all of the above can be done without worrying about temporary files, unique file names, I/O errors, or any of the other hassles that go along with physical file interaction.

Here is a very simple ColdFusion form that gathers data from the user, converts that data into a PDF-based "Certificate" using CFDocument, and then sends out the certificate using CFMail:

 Launch code in new window » Download code as text file »

  • <!--- Param form values. --->
  • <cfparam name="form.submitted" type="boolean" default="false" />
  • <cfparam name="form.type" type="string" default="" />
  • <cfparam name="form.name" type="string" default="" />
  • <cfparam name="form.email" type="string" default="" />
  •  
  • <!--- Create an array to hold our form validation errors. --->
  • <cfset errors = [] />
  •  
  •  
  • <!--- Check to see if the form has been submitted. --->
  • <cfif form.submitted>
  •  
  • <!--- Validate the form data. --->
  •  
  • <!--- Validate certificate type. --->
  • <cfif !len( form.type )>
  •  
  • <cfset arrayAppend(
  • errors,
  • "Please enter the type of Certificate that you want to create. Example: World's Greatest Butt."
  • ) />
  •  
  • </cfif>
  •  
  • <!--- Validate name. --->
  • <cfif !len( form.name )>
  •  
  • <cfset arrayAppend(
  • errors,
  • "Please enter the name that will be displayed on the certificate."
  • ) />
  •  
  • </cfif>
  •  
  • <!--- Validate email. --->
  • <cfif !isValid( "email", form.email )>
  •  
  • <cfset arrayAppend(
  • errors,
  • "Please enter a valid email address to whom the certificate will be sent."
  • ) />
  •  
  • </cfif>
  •  
  •  
  • <!--- Check to see if we have any form errors. --->
  • <cfif !arrayLen( errors )>
  •  
  • <!---
  • Since we don't have any errors's let's create the
  • certiciate as a PDF using the CFDocument tag. We're
  • going to assign the document content to a variable
  • so that we can attach it to the email without going
  • to the file system.
  • --->
  • <cfdocument
  • name="certificate"
  • format="PDF"
  • pagetype="custom"
  • pageheight="5"
  • pagewidth="6.5"
  • margintop="0"
  • marginbottom="0"
  • marginright="0"
  • marginleft="0"
  • unit="in"
  • fontembed="true"
  • backgroundvisible="true"
  • localurl="true">
  •  
  • <cfoutput>
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <style type="text/css">
  •  
  • body {
  • background-image: url( "certificate.jpg" ) ;
  • background-position: center center ;
  • background-repeat: no-repeat ;
  • font-family: arial ;
  • margin: 0px 0px 0px 0px ;
  • padding: 0px 0px 0px 0px ;
  • }
  •  
  • div##name,
  • div##type,
  • div##day,
  • div##month,
  • div##year {
  • position: absolute ;
  • text-align: center ;
  • }
  •  
  • div##name,
  • div##type {
  • font-size: 24px ;
  • font-weight: bold ;
  • }
  •  
  • div##day,
  • div##month,
  • div##year {
  • font-size: 14px ;
  • }
  •  
  • div##name {
  • left: 185px ;
  • top: 152px ;
  • width: 255px ;
  • }
  •  
  • div##type {
  • left: 162px ;
  • top: 225px ;
  • width: 300px ;
  • }
  •  
  • div##day {
  • left: 172px ;
  • top: 268px ;
  • width: 50px ;
  • }
  •  
  • div##month {
  • left: 282px ;
  • top: 268px ;
  • width: 145px ;
  • }
  •  
  • div##year {
  • left: 440px ;
  • top: 268px ;
  • width: 57px ;
  • }
  •  
  • </style>
  • </head>
  • <body>
  •  
  • <div id="name">
  • #form.name#
  • </div>
  •  
  • <div id="type">
  • #form.type#
  • </div>
  •  
  • <div id="day">
  • #day( now() )#
  • </div>
  •  
  • <div id="month">
  • #monthAsString( month( now() ) )#
  • </div>
  •  
  • <div id="year">
  • #year( now() )#
  • </div>
  •  
  • </body>
  • </html>
  •  
  • </cfoutput>
  •  
  • </cfdocument>
  •  
  •  
  • <!---
  • Now that we have the content of our CFDocument-generated
  • certificate in our certificate variable, we can easily
  • attach it to the outgoing email.
  • --->
  • <cfmail
  • to="#form.email#"
  • from="info@certificiates.com"
  • subject="Congratulations #form.name#!"
  • type="html">
  •  
  • <h1>
  • Congratulations #form.name#,
  • </h1>
  •  
  • <p>
  • You have been awarded the attached certiciate of
  • appreciation!
  • </p>
  •  
  •  
  • <!---
  • Attach the content of the CFDocument tag to the
  • outgoing email.
  • --->
  • <cfmailparam
  • file="certificiate.pdf"
  • type="application/pdf"
  • content="#certificate#"
  • />
  •  
  • </cfmail>
  •  
  •  
  • <!---
  • The form has been successfully procesed, so forward
  • to confirmation page.
  • --->
  • <cflocation
  • url="confirmation.cfm"
  • addtoken="false"
  • />
  •  
  • </cfif>
  •  
  • </cfif>
  •  
  •  
  • <cfoutput>
  •  
  • <!--- Set the content and reset the output buffer. --->
  • <cfcontent type="text/html" />
  •  
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  • <html>
  • <head>
  • <title>ColdFusion CFDocument And CFMail Demo</title>
  • </head>
  • <body>
  •  
  • <h1>
  • ColdFusion CFDocument And CFMail Demo
  • </h1>
  •  
  • <p>
  • Please fill out the following form and a
  • "Certificate of Appreciation" will be automatically
  • created and emailed to the given address.
  • </p>
  •  
  •  
  • <!--- Check to see if we have any form errors. --->
  • <cfif arrayLen( errors )>
  •  
  • <h3>
  • Please review the following:
  • </h3>
  •  
  • <ul>
  • <cfloop
  • index="error"
  • array="#errors#">
  •  
  • <li>
  • #error#
  • </li>
  •  
  • </cfloop>
  • </ul>
  •  
  • </cfif>
  •  
  •  
  • <form action="#cgi.script_name#" method="post">
  •  
  • <!--- The form submission flag. --->
  • <input type="hidden" name="submitted" value="true" />
  •  
  • <p>
  • <label>
  • Certificate:<br />
  • <input
  • type="text"
  • name="type"
  • value="#form.type#"
  • size="40"
  • maxlength="50"
  • />
  • </label>
  • </p>
  •  
  • <p>
  • <label>
  • Name:<br />
  • <input
  • type="text"
  • name="name"
  • value="#form.name#"
  • size="40"
  • maxlength="50"
  • />
  • </label>
  • </p>
  •  
  • <p>
  • <label>
  • Email:<br />
  • <input
  • type="text"
  • name="email"
  • value="#form.email#"
  • size="40"
  • maxlength="100"
  • />
  • </label>
  • </p>
  •  
  • <p>
  • <input type="submit" value="Send Certificate" />
  • </p>
  •  
  • </form>
  •  
  • </body>
  • </html>
  •  
  • </cfoutput>

By supplying the CFDocument tag with a Name attribute, Coldfusion will store the generated PDF document as a binary variable in the supplied variable name, "certificate." Then, using the Content attribute of the CFMailParam tag, we can take that binary ColdFusion variable and attach it directly to the outgoing email.

Running the above code, I end up with the following email:

 
 
 
 
 
 
Email Generated By ColdFusion's CFDocument And CFMail Tag. 
 
 
 

... which has the following PDF attachment:

 
 
 
 
 
 
Adobe PDF Generated By ColdFusion's CFDocument And CFMail Tag. 
 
 
 

Works like a charm. I hope that helps.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Sep 4, 2009 at 7:47 PM // reply »
18 Comments

I'm not sure why I noticed this, but I like how the cfmail tag is sending the email from info@certificiates.com and the screenshot shows the email coming from info@certiciates.com. What exactly were you trying to spell? Certificates? A little over excited for the long weekend?

Aside from that, nice example.


Sep 4, 2009 at 11:02 PM // reply »
78 Comments

@Ben,

Just a nitpick about something we both know - but which can cause some unintended confusion in someone who isn't on his guard.

========
Coldfusion will store the generated PDF document as a binary variable in the supplied variable name, "certificate."
========

ColdFusion will store the generated PDF document as a binary value, which is referenced by the variable named "certificate".

Values are data, while variables are containers for data or pointers to data.

Justice


Sep 5, 2009 at 1:44 AM // reply »
1 Comments

This is a slight variation on the technique we use on WillYourself.com

Works well.


Sep 6, 2009 at 10:36 AM // reply »
6,516 Comments

@Tony,

Yeah, I noticed that right after I posted the blog entry. I went back to fix it in the code and was too lazy to make the screen shot again - I had to run out for dinner plans. I see, however, now that I even misspelled the correction with in the code. Ooops :)

@Justice,

Ahh, good point - you always keep me vigilant on my fast-and-lose use of language.

@Gary,

Yeah, ColdFusion makes this stuff so simple.


Sep 6, 2009 at 2:52 PM // reply »
2 Comments

thank you man


Sep 9, 2009 at 5:41 AM // reply »
14 Comments

Where can I meet this Joanna at?

-- Nice tutorial simple stuff.


Sep 10, 2009 at 1:19 PM // reply »
23 Comments

Will this work in CF7?

I was under the impression that any code AFTER a closing cfdocument tag would not execute.

@Jody - I'm with you. Where's Joanna?


Sep 12, 2009 at 10:13 PM // reply »
6,516 Comments

@Brian,

It depends on when the "name" attribute was added. I think no processing post-CFDocument would only occur if you were outputting the content of the PDF to the browser.

But, more importantly, you cannot use the Content attribute of the CFMailParam until CF8. As such, you would need to write the PDF to file and then use the File attribute instead.


Nov 13, 2009 at 10:46 AM // reply »
1 Comments

Wow thx for this great resource ! so useful ! I put it in my bookmarks...


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »
Nov 20, 2009 at 5:23 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Todd, Ahh, gotcha, yeah that makes sense. ... read »
Nov 20, 2009 at 5:17 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
Ben, sorry if I didn't make this clear. You can make it work like that if you want, just put <cfset session.foo = 1> (and <cfset application.foo = 1>) in your OnRequestStart() and it reve ... read »