Using CFMAIL to send attachments stored in memory
Awhile back I was looking for a way to send e-mail attachments in CFMX without writing data to disk. That solution uses the Javamail API to directly send a e-mail with attachments to an SMTP server. This method also completely bypasses the CF mail spool.
Charlie Arehart linked to the article from an article he wrote about storing CFDOCUMENT and CFREPORT contents in a variable. In the comments on his post, Jon Wolski posted a solution that uses the built-in ColdFusion tags CFMAIL and CFMAILPART. So, I thought I'd re-do my original example using Jon's technique in this post—just so you can see an example of both methods.
Below is some source code that will show you how to use the CFMAIL tag to send a multipart message that contains:
- Plain Text
- HTML (with embedded images)
- Two file attachments from binary data stored in memory
<cfdocument format="pdf" name="binPdf">
<h1>
A PDF Document
</h1>
<p>
This is a document rendered by the cfdocument tag
at <cfoutput>#dateFormat(now(), "mmmm dd, yyyy")#
#lCase(timeFormat(now(), "h:mmtt"))#</cfoutput>.
</p>
<table width="50%" border="2" cellspacing="2" cellpadding="2">
<tr>
<td><strong>Name</strong></td>
<td><strong>Role</strong></td>
</tr>
<tr>
<td>Bill</td>
<td>Lead</td>
</tr>
<tr>
<td>Susan</td>
<td>Principal Writer</td>
</tr>
<tr>
<td>Adelaide</td>
<td>Part Time Senior Writer</td>
</tr>
<tr>
<td>Thomas</td>
<td>Full Time for 6 months</td>
</tr>
<tr>
<td>Michael</td>
<td>Full Time for 4 months</td>
</tr>
</table>
</cfdocument>
<!---// create a png chart and save it to a variable //--->
<cfchart name="binChart" format="png" font="arialunicodeMS" xaxistitle="Month" yaxistitle="Degrees Celsius" showlegend="yes">
<cfchartseries type="line" serieslabel="Europe">
<cfloop index="i" list="Apr,May,Jun,Jul,Aug,Sep">
<cfchartdata item="#i#" value="#RandRange(12,42)#">
</cfloop>
</cfchartseries>
<cfchartseries type="line" serieslabel="USA">
<cfloop index="j" list="Apr,May,Jun,Jul,Aug,Sep">
<cfchartdata item="#j#" value="#RandRange(12,42)#">
</cfloop>
</cfchartseries>
</cfchart>
<cfscript>
// config
sSubject = "CFMAIL w/diskless attachment!";
sAddyTo = "to@yourcompany.com";
sAddyFrom = "from@yourcompany.com";
// create the boundary marker indicating each new multi-part section
sBoundary = createUUID();
// create the CID for the embedded image
sCID = "23abc@pc27";
</cfscript>
<cfmail to="#sAddyTo#" from="#sAddyFrom#" subject="#sSubject#">
<cfmailpart type="multipart/mixed; boundary=#chr(34)##sBoundary##chr(34)#">
--#sBoundary#
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
<html>
<head>
<title>HTML E-mail</title>
</head>
<body>
<h1>
You like using HTML e-mail in CFMX.
</h1>
<p>
<img src=cid:#sCID# />
</p>
</body>
</html>
--#sBoundary#
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
You like using plain text in CFMX.
--#sBoundary#
Content-Type: application/pdf
Content-Disposition: attachment; filename=test-file.pdf
Content-Transfer-Encoding: Base64
#binaryEncode(binPdf, "base64")#
--#sBoundary#
Content-Type: image/png
Content-Disposition: attachment; filename=chart.png
Content-Transfer-Encoding: Base64
#binaryEncode(binChart, "base64")#
--#sBoundary#
Content-Type: image/png
Content-Disposition: attachment; filename=chart2.png
Content-ID: <#sCID#>
Content-Transfer-Encoding: Base64
#binaryEncode(binChart, "base64")#
--#sBoundary#--
</cfmailpart>
<cfmailpart type="application/x-unsupported">
This should not be rendered by a mail user agent because it does not support the MIME-type.
</cfmailpart>
</cfmail>
Comments
One thing that was pointed out by someone else on CF-Talk was that this method does *not* generate a syntactically correct SMTP message. This means some mail clients may not correctly interpret the message.
For this reason, I'd suggest still using the Javamail API method.
As a comment above mentions, you would probably be better off using the method talked about here:
http://blog.pengoworks.com/index.cfm/2007/2/8/Send...
That should show you off enough code to get you up and running.
As the comments state, this does not produce a syntactically correct SMTP message--which could be your problem.
The better solution is to use:
http://blog.pengoworks.com/index.cfm/2007/2/8/Send...
Also, the CF8.01 allows you to due this natively.
This has all been very helpful and enlightening, thanks for posting it!
But I'm still a little bit stuck. I'd like to send an ics (iCal) file without having to save it as a file. I've been able to create a "file" in memory using the <cfcontent> tag that the user could download from the website. But, what we really want is to send them an email that is an invitation that they could accept or decline. Any suggestions?
Thanks!
Ember
you said
"Also, the CF8.01 allows you to due this natively. "
to clarify are you saying that CF8.01 allows you to use the method seen in this example natively or the method used on the example you linked to?
thanks in advance,
tim
In CF 8.01 they introduced new attributes/tags that allow you to send an attachment from memory. See the documentation for more information (I believe its the cfmailparam tag that the functionality was tied to, but can't recall off the top of my head.)
For those wishing to email an attachment from an uploaded file or a file that only is stored on the sever temporarily they can use the REMOVE="true" attribute on the CFMAILPARAM which will remove the file once the email has cleared the CFMAIL spool. Shown in a great example by Ben Nadel here: http://www.bennadel.com/blog/1214-New-ColdFusion-C...
Thanks for your quick reply and hopefully this helps someone out after I spent a while searching for something that I felt would have been a grand omission in CF8 in light of all the new PDF capabilities.
Nice work. I was struggling to find a solution for some on the fly PDF CFMail attachments. You solution worked like a charm! Thanks for sharing.
Bob L.
Once again, many many thanks!
-Amjad

Thanks for sharing.