Ask a Jedi: Sending a dynamic PDF via email

This post is more than 2 years old.

Chas asked:

Thanks for your great series on working with PDFs. I have a question I hope you can help me with. I want to create a PDF (simple enough using cfdocument) but then I would like to email it without having to write it disk using a filename. I can create it and save to "name", but I can't seem to be able to use that in the cfmailparam. Any way to generate a PDF and email it on the fly?

Turns out this is rather simple, if you are using ColdFusion 8.0.1. CF801 added the ability to use cfmailparam to attach files stored in a variable. For example:

<cfdocument format="pdf" name="pdfdoc"> <h1>Snazzy PDF</h1>

Here is your cool PDF that is dynamic: <cfoutput>#randRange(1,100)#</cfoutput> </cfdocument>

<cfmail to="ray@camdenfamily.com" from="foo@foo.com" subject="Your PDF"> <cfmailparam file="doc.pdf" content="#pdfdoc#"> Attached please find your cool PDF. Enjoy! </cfmail>

Done.

The first part of the template creates a simple dynamic PDF. Then I mail it to myself. Note that cfmailparam uses both file and content attributes. The content will be the actual data attached to the email while the file attribute will be used for the file name.

In case you are wondering why this isn't in the docs, or why I didn't do this in my 'emailing cfchart' blog post, it is simply the fact that the main docs have not been updated for 8.0.1. You will be able to find this documented, along with everything else new, in the 8.0.1 release notes: http://www.adobe.com/support/documentation/en/coldfusion/releasenotes.html#801

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Scott posted on 1/23/2009 at 1:01 AM

Ahh, very nice. I hadn't realized this. If you're not running 8.0.1 you could utilize the technique that Dan outlines <a href="http://blog.pengoworks.com/...">here</a>.

Comment 2 by Scott posted on 1/23/2009 at 1:03 AM
Comment 3 by tanguyr posted on 1/23/2009 at 1:04 AM

it has been a couple of years since i worked full-time with coldfusion, but it still just blows me away when i see stuff like this - regular cf devs take this for granted, but you just dynamically generated a pdf file and sent it via email in less than 10 lines of code. I have yet to see another web dev language that could do this (at least without enless lines of behind the scenes configuration).

Regs,
/t

Comment 4 by Jonathan posted on 1/23/2009 at 6:56 PM

argh!

I needed to do this in a project a couple months back and went to the trouble of using some nasty java class to send the email.

oh well, nice to know for the next time

Comment 5 by Brian W. posted on 2/10/2009 at 10:57 PM

I'm currently using this method to send pdf's within my company. I'm noticing the memory on the server starting to spike and hold pretty steadily now that word is getting around about my app.

My question is: Do you think it would be beneficial to clear the variable holding that document after its been sent? If so, can you advise on how to best accomplish this?

I'm already dynamically creating a unique "name" (w/in cflock) for the pdf so there would be no problem clearing it if you folks think that would help.

Thanks!

Comment 6 by Raymond Camden posted on 2/11/2009 at 7:13 AM

Hmm, if you are generating the same PDF over and over again, it may be better to save it to the file system and use that version for future emails.

Comment 7 by Brian W. posted on 2/12/2009 at 12:30 AM

Thanks for the reply Ray!

They're all unique reports based on the users selections; however, I lowered the session timeout and that seemed to have mitigated the high memory issue I was running into.

Thanks again, and keep up the amazing work. Your blog has helped me numerous times. I come here when I can't get "out side the box" for a little Coldfusion Jedi insight :)

Brian.

Comment 8 by Michael Evangelista posted on 2/26/2009 at 10:36 PM

This is really helpful - I need to do something similar, with a twist... in this case the client is a small govt agency. They are developing some simple PDF forms in livecycle, and I'm learning how to integrate the PDF form submission with CF.

If possible, we'd like a user to submit a PDF form in their browser, and then we:

1) save the pdf to the server, looking just like the form they filled out, with their data in place

2) email a copy of same (once saved to server emailing is no problem - that's this blog entry!)

AND

3) extract just the data from the form (ala 'form.variablename' in cf), and save it to a database, separate from the actual PDF layout.

Can it be done?

I am just starting to play with their existing PDF forms and the 'submit' options seem somewhat limited... which makes me think I am missing something.

Comment 9 by Raymond Camden posted on 2/27/2009 at 9:10 PM

@ME - Yes, I think you just need to look into cfpdfform. I haven't played with it a lot, but it should allow for this.

Comment 10 by Michael Evangelista posted on 2/27/2009 at 10:17 PM

as usual, cf says in one tag or command what i couldn't even say very well in 12 lines.

I knew i could 'make' a pdf form with cfpdfform ( #1 below), but didn't realize it did these other things, too. Very cool, thanks.

+++
* Embed an interactive form created in Acrobat LiveCycle in a PDF document. You use the cfpdfform tag to embed the PDF form in a cfdocument tag.
* Render an existing form created in Acrobat or LiveCycle. This includes prefilling fields from a database or an XML data file and processing form data from an HTTP post or PDF submission.
* Extract or prefill values in stored PDF forms and save the output to a file or use it to update a data source.

+++

ps TOO weird. The captcha that came up for this reply was "m e"

Comment 11 by George posted on 6/24/2009 at 1:20 AM

So glad I found this - just saved me a ton of work!

Comment 12 by George posted on 6/24/2009 at 7:29 PM

So after I tried to implement - I realized that I am using 7 on this server. Is there a similar method - or something like it - that can be used there?

Comment 13 by Raymond Camden posted on 6/25/2009 at 4:30 PM

You can send mail with attachments in CF7 - you just can't use an in-memory variable like I did. You would need to save the data to the file system and then clean it up later.

Comment 14 by Andrew posted on 8/14/2009 at 2:50 PM

Hi Ray

I am getting the following error when attaching my cfdocument via the cfmailparam tag:
ByteArray objects cannot be converted to strings.

I know the pdf is being generated as I wrote it to desk to check this. My code is as follows:

<cffunction name="sendPDF" output="false" access="public" returntype="struct">
<cfargument name="replyto_name" required="false" type="String" default="">
<cfargument name="replyto_email" required="false" type="String" default="">
<cfargument name="to_name" required="false" type="String" default="Admin">
<cfargument name="to_email" required="false" type="String" default="#application.settings.adminEmail#">
<cfargument name="subject" required="false" type="String" default="Form Email">
<cfargument name="type" required="false" type="String" default="html">
<cfset var thepath = '#ExpandPath("images/giftvoucher/logo.jpg")#'>
<cfset var thepath2 = '#ExpandPath("images/giftvoucher/podplayshop.jpg")#'>
<cfset var logopath = '#ExpandPath("images/logo.jpg")#'>
<cfset result.isSuccess = false>
<cfset result.message = "An unknown error occurred.">
<cfset result.data = "">
<cfset thepath = 'http://www.mydomain.com/tes...
<cfset thepath2 = 'http://www.mydomain.com/tes...
<cfset logopath = 'http://www.mydomain.com/tes...
<cftry>
<!--- CREATE THE PDF --->
<cfdocument format="PDF" name="voucherpdf">
<cfoutput>
<div style="text-align:center;">
<div style="width:700;border:1px solid orange;">
<div style="float:right;width:337px;text-align:left;">
<img src='http://www.mydomain.com/tes... width='337' height='101' />
<img src='http://www.mydomain.com/tes... width='330' height='103' />
<p>side content goes here</p>
</div>
<div style="float:left;text-align:left;">
<p>The main content will go here...</p>
</div>
<br clear="all"/>
</div>
</div>
</cfoutput>
</cfdocument>
<!--- SEND THE MAIL --->
<cfmail to = "#ARGUMENTS.replyto_name#<#ARGUMENTS.replyto_email#>" from = "#application.settings.systemEmail#" subject = "#ARGUMENTS.subject#" server="#application.settings.smtpServer#" username="#application.settings.systemEmail#" password="#application.settings.systemEmailPassword#" type="html" replyto="#ARGUMENTS.to_name#<#ARGUMENTS.to_email#>">
<cfmailparam file='doc.pdf' contentID="#voucherpdf#">
<cfsavecontent variable="theEmail">
<cfoutput>
<center>
<cfmailparam file='#logopath#' contentid='mainlogo' disposition='inline' />
<img src='cid:mainlogo' width='400' height='130' alt='Company Name' />
<p>Attached is your voucher.</p>

<p>Hope you enjoy spending it :)</p>

<p>Kind Regards</p>
</center>
</cfoutput>
</cfsavecontent>
<cfoutput>#theEmail#</cfoutput>
</cfmail>
<cfset result.data = #theEmail#>

<cfcatch>
<cfset result.message = '#cfcatch.message#'>
</cfcatch>
</cftry>
<cfreturn result>
</cffunction>

The code calling this function is:

<cfsilent>
<cfset variables.email = createObject("component","components.utility").sendPDF("MyName",APPLICATION.settings.ownerEmail)>
</cfsilent>
<cfoutput>
#VARIABLES.email.message#
</cfoutput>

Please point me in the right direction.
Thanks in advance

Comment 15 by Raymond Camden posted on 8/14/2009 at 4:11 PM

The contentid value of cfmailparam is a string, not binary data.

Comment 16 by Andrew posted on 8/14/2009 at 4:13 PM

Ignore my previous post...

I was using 'contentID' instead on 'content'
<cfmailparam file='doc.pdf' contentID="#voucherpdf#">
<cfmailparam file='doc.pdf' content="#voucherpdf#">

Comment 17 by clicque posted on 10/20/2009 at 11:32 AM

I'm using a similor code to send dynamic pdf, i've a strange problem with the image background. The two first pdf contains the images but all the other are not included.
Here is the code i'm using

<cfloop list="#form.fournisseur_id#" index="index">
<cfquery name="Getfournisseur" datasource="#application.dsn#">
SELECT * from fou
WHERE fou_id=#index#
</cfquery>

<cfdocument pagetype="A4" format="pdf" fontembed="yes" backgroundvisible="true" name="annexe">
<cfoutput>
<html>
<head>
<style >
.backgroundimage {
background-image: url(/images/background.gif);
background-repeat: no-repeat;
height:2339px;
width:1654px;
position:absolute;
top:-100px;
visibility: visible;
left: -50px;
z-index: 0;
}
</style>
</head>
<body>

<div class="backgroundimage"></div>
<div style="z-index:1; position:absolute; font-size:33px; padding-left:50px;">
<DIV style="padding-left:1000px; font-weight:bold; padding-top:500px; ">
#getfournisseur.name#<br>
#getfournisseur.adress#<br>
</div>

<p>
#replace(form.contenu,"#chr(13)#","<br>","all")#
</p>
<br><br>
</div>
</body>
</html>
</cfoutput>
</cfdocument>
<cfmail from="#application.from#" to="#getfournisseur.email#" subject="info" type="HTML">
<cfmailparam file="annexe.pdf" content="#annexe#">
</cfmail>
</cfloop>

Comment 18 by Anthony Escribens posted on 4/30/2010 at 12:59 AM

Hi Ray,

I tried your example and are having an issue opening the PDF file. I get the following Adobe Reader error:

"Adobe Reader could not open 'document.pdf' because it is either not a supported file type or because the file has been damanged (for example, it was sent as an email attachment and wasn't correctly decoded)."

I checked the properties of the file and was listed to have a PDF Version: 0.0 (under the PDF tab).

My Coldfusion Email Client is SmarterMail sending to a GMAIL account, if this makes a difference.

Any suggestions?

Thanks!
Anthony

Comment 19 by Raymond Camden posted on 4/30/2010 at 1:03 AM

First - add a line of code to save the PDF binary to the file system. See if the file is ok there.

Comment 20 by Anthony Escribens posted on 4/30/2010 at 3:48 PM

Ray - Saving the file before attaching it to cfmail seems to be doing the trick, but there is a way to generate the pdf and mail it without saving it? Or is it best practice to first save the file?

Comment 21 by Raymond Camden posted on 4/30/2010 at 5:09 PM

Well, I wouldn't save it if you didn't need to. So - let's see why it didn't work for you. Are you running 801? (Note I said 801, not 8.)

Comment 22 by Anthony Escribens posted on 5/7/2010 at 7:06 PM

Sorry about the late response. I just checked the server and are running version 8,0,1,195765.

Comment 23 by Raymond Camden posted on 5/7/2010 at 7:18 PM

Ok, interesting. Um, well wow. I'm out of ideas. :) You can file a bug report with Adobe, but it definitely worked for me. But if your having success with using a 'real' file, for now then I'd just stick with that. Sorry I don't have a better answer.