Ask Ben: Creating A PDF And Attaching It To An Email Using ColdFusion
Posted September 4, 2009 at 5:39 PM
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:
| | | | | |
| | ![]() | | ||
| | | |
... which has the following PDF attachment:
| | | | | |
| | ![]() | | ||
| | | |
Works like a charm. I hope that helps.
Download Code Snippet ZIP File
Post Comment | Ask Ben | Other Searches | Print Page
Newer Post
Using IIS URL Rewriting And Application.cfc's OnMissingTemplate() Event Handler
Older Post
RewriteCond Directives Evaluated After RewriteRule Directives In URL Rewriting
Reader 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.
@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
This is a slight variation on the technique we use on WillYourself.com
Works well.
@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.
thank you man
Where can I meet this Joanna at?
-- Nice tutorial simple stuff.
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?
@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.
Wow thx for this great resource ! so useful ! I put it in my bookmarks...
The content attribute is really awesome! Is possible to refer me to sample code to achieve the same result in coldfusion 7 MX?
Thanks
@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.
Have you got any reference to code explaining the procedure to use cfdocument, file to disk and attach to email?
@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).
Is anyone having trouble with Sandbox Security with this?
pass access denied (java.io.FilePermission test.pdf read)
@Galen,
Is this on a file you just created? Or one that was existing?
@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.
@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?
@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.
@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.
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.
@Rob,
Thanks Rob! I appreciate the comment.
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?
@Victor,
Do you have an email client that is built using ColdFusion? I am confused as to what you are asking?
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
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?
@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".
Hadnt worked with iframes like that, maybe I will give it a wirl. I will keep you posted.
vic
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
@Victor,
Sounds like a plan. Glad you got something worked out.






