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  |  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 »
86 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 »
7,572 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 »
19 Comments

Where can I meet this Joanna at?

-- Nice tutorial simple stuff.


Sep 10, 2009 at 1:19 PM // reply »
31 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 »
7,572 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...


Feb 8, 2010 at 11:20 AM // reply »
2 Comments

The content attribute is really awesome! Is possible to refer me to sample code to achieve the same result in coldfusion 7 MX?

Thanks


Feb 8, 2010 at 12:29 PM // reply »
7,572 Comments

@Johan,

I don't know of a way to accomplish this pre-CF8 without writing the file to disk and using the File attribute, sorry.


Feb 9, 2010 at 12:57 AM // reply »
2 Comments

Have you got any reference to code explaining the procedure to use cfdocument, file to disk and attach to email?


Feb 9, 2010 at 7:47 AM // reply »
7,572 Comments

@Johan,

I don't think I have one off hand. Basically, you'd just want to use the File attribute of CFDocument to save the PDF to disk. Then, you'd want to use the File attribute of CFMailParam to attach it to the mail.

Just be careful about deleting the file; if you plan to delete the file right after sending out the email, you have to turn OFF spoolenable on the mail (otherwise you'll delete the file before the mail goes out).


Feb 9, 2010 at 4:51 PM // reply »
3 Comments

Is anyone having trouble with Sandbox Security with this?

pass access denied (java.io.FilePermission test.pdf read)


Feb 10, 2010 at 8:20 AM // reply »
7,572 Comments

@Galen,

Is this on a file you just created? Or one that was existing?


Feb 10, 2010 at 11:10 AM // reply »
3 Comments

@Ben,

I'm following your method and trying to attach the generated pdf without using the file system at all. So no "test.pdf" file is being created.


Feb 10, 2010 at 10:42 PM // reply »
7,572 Comments

@Galen,

Hmmm, that's really weird. I wonder if CFDocument needs file permissions even to run (perhaps for scratch file space). I have not heard of that. Are you sure you're not using the FileName attribute on the CFDocument tag?

What code item is the error being thrown on? The PDF creation? Or the email attachment? Can you see this in the stack trace?


Feb 11, 2010 at 1:22 PM // reply »
3 Comments

@Ben,

I'm not using the filename attribute of CFDocument; the error is being thrown at the line file="certificiate.pdf" inside CFMailparam.

I'm baffled. Thanks for the feedback.


Feb 11, 2010 at 10:14 PM // reply »
7,572 Comments

@Galen,

I am as baffled as you. ColdFusion must be trying to write the PDF to a temp file or something and cannot access the file (write permissions). Very odd though.

Try outputting the temp directory to see what directory it is:

#getTempDirectory()#

This *might* be where CF is trying to create a temp file. Make sure the directory exists.


Mar 1, 2010 at 4:21 PM // reply »
3 Comments

Ben,

How is it possible that every time I search for completely new issues I run into with CF, you already have an article on it. Amazing my man. Keep up the good work. Your site is a valuable asset to the CF community.


Mar 1, 2010 at 4:25 PM // reply »
7,572 Comments

@Rob,

Thanks Rob! I appreciate the comment.


Mar 2, 2010 at 9:58 AM // reply »
5 Comments

This shows how to embed a pdf in an outgoing email message. How do you attach the pdf to an email message you have'nt sent yet. In other words, open your email client and pre-view what you are about to manually send, with the attachment attached to the email?


Mar 2, 2010 at 10:00 AM // reply »
7,572 Comments

@Victor,

Do you have an email client that is built using ColdFusion? I am confused as to what you are asking?


Mar 2, 2010 at 10:23 AM // reply »
5 Comments

we run coldfusion 7,8 dev/prod. I have implemented sending an email and attaching a dynamically created PDF on the fly, but now I want to open my email client in a coldfusion app,
simple enough to open-

(a href="mailto: etc etc.)

-and attach a pdf document before I sending the email (using the email client 's send). By contrast if I use:
cfmail to="" etc etc tag

this will send the email immediately.
-I want to open the email that I am sending, and see that the pdf was attached. Then I can send it like I normally would send an email. This also lets me make any changes to my text in the email before sending. sorry to be vague..
thanks for prompt reply! First time posting.
vic


Mar 2, 2010 at 10:55 AM // reply »
5 Comments

I got it, I'll just use the code I currently have that sends an email with the dynamic PDF attachment, but instead of sending it to the intended party, I will send it to myself, then I can preview it, and foward it to the intended recipient using the email clients send. The only problem with this though is that the intended recipients email address is in a database that has to be looked up, and gets injected into the mailto="" parameter arrgggghhh. I wonder if I can populate the foward to variable?


Mar 2, 2010 at 11:05 AM // reply »
7,572 Comments

@Victor,

If you have a form where you are selecting the PDF, perhaps you could create an intermediate page (after form, before sending) where the uploaded PDF gets displayed in an iFrame? This way, you could have the option to "Continue (send email)" or "Edit Message".


Mar 2, 2010 at 12:17 PM // reply »
5 Comments

Hadnt worked with iframes like that, maybe I will give it a wirl. I will keep you posted.
vic


Mar 2, 2010 at 4:42 PM // reply »
5 Comments

Thought I would post u back what i did. First so u understand whats happenning, I compose an email that contains static text together with a blank pdf form that is dynamically populated with applicant information from a database query, and attached and sent to a recipient using cfmail and cfdocument tag.

What I was trying to do instead of this was to provide a link using mailto: to let the user open their email client on their local machine and attach this pdf file.

This was hard to do because the pdf is created dynamically and is not saved on the server.
so, i instead send the user the email with the embedded pdg, and let them do whatever they want with it, before fowarding it to the designated email recipient which I convieninetly include in the text of the email for them to copy and paste.
-vic


Mar 2, 2010 at 7:54 PM // reply »
7,572 Comments

@Victor,

Sounds like a plan. Glad you got something worked out.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »
Jim
Mar 19, 2010 at 4:44 PM
Shoot 'Em Up Starring Clive Owen And Paul Giamatti
I actually enjoyed this movie quite a lot. It was different, certainly, but I think they were going for more of a Quentin Tarentino-"wow, that was weird"-vibe than an actual spoof. Once I realize ... read »
Mar 19, 2010 at 4:34 PM
An Intensive Exploration Of jQuery With Ben Nadel (Video Presentation)
Hey I guess the video is down. Is there anyway you can upload to youtube or vimeo or some other service? Greatly appreciated. ... read »
Mar 19, 2010 at 4:24 PM
ColdFusion CFPOP - My First Look
@Ben Thanks for the follow up! The root of the problem had to do with being able to trace bounced emails to specific records in a DB table. Let's say you run an email campaign and you get 1,000 bou ... read »
Mar 19, 2010 at 4:15 PM
SQL COUNT( NULLIF( .. ) ) Is Totally Awesome
Thank you Ben and Tony! Either of these work for the summary report I am working on and the info is much appreciated! I think I like Tony's a little better because I won't have to educate every ... read »
Mar 19, 2010 at 3:35 PM
ColdFusion Path Usage And Manipulation Overview
@Ben, Sorry. Clarification. expandpath worked for me in application.cfc, but not in other templates. ... read »