Tag Archives: ColdFusion

Cfpop with Gmail and Other Pop Accounts: Processing Emails and Attachments

Accessing messages and attachments in gmail via cfpop can be done in a relatively straightforward way. An example of connecting to and reading messages and attachments from gmail is shown here.

Enable POP on gmail

First things first. POP access must be enabled on the gmail (or other) account before attempting to download the mail. To enable POP, go to the Forwarding/POP and IMAP panel in Settings. Enable POP and save the settings. Tip: you can reset this and download the same messages again while testing by enabling pop again.
gmail pop settings panel

SSL

gmail requires SSL to access it via POP. Unfortunately, the cfpop tag does not include SSL. It can be turned on with the following code:

    <cfset javaSystem = createObject("java", "java.lang.System") />
    <cfset jProps = javaSystem.getProperties() />
    <cfset jProps.setProperty("mail.pop3.socketFactory.class", "javax.net.ssl.SSLSocketFactory") />
    <cfset jProps.setproperty("mail.pop3.port",995) />
    <cfset jProps.setProperty("mail.pop3.socketFactory.port", 995) />

cfpop

Use cfpop wrapped in a cftry surrounded by a cflock to retrieve the emails. POP is slow and may timeout on you if there are lots of messages and lots of attachments. If that is the case, you may want to retrieve just the headers and selectively grab the messages using the UID. This example grabs everything.

<cflock name="cfpop-#form.username#" type="exclusive" timeout="50">

           <cftry>

              <cfpop server="#form.popserver#" username="#form.username#" password="#form.pwd#"
          action="getAll" name="getEmail" attachmentpath="#attachmentFolder#" generateUniqueFilenames="true">

           <cfcatch type="any">
           <h2 class="error">Error Message</h2>
            <p><strong>Type:</strong> #CFCATCH.Type#</p>
            <p><strong>Message:</strong> #CFCATCH.Message#</p>
            <p><strong>Detail:</strong> #CFCATCH.Detail#</p>
            <cfabort>
        </cfcatch>

        </cftry>

</cflock>

Attachments

By default the attachments will be downloaded to the temp directory of the server. You can find out where that is with the GetTempDirectory() function.

<cfoutput>#GetTempDirectory()#</cfoutput>

Or, you could create a folder specifically for the attachments.

<cfset attachmentFolder = ExpandPath("attachments") />

Attachment names and files are tab-separated lists in ColdFusion. Putting these lists in an array makes for easy looping later. Set this up by creating the empty arrays.

<!--- Array for attachment name(s) --->
<cfset attachmentNameArray = ArrayNew(1) />

<!--- Array for attachment file(s) --->
<cfset attachmentFileArray = ArrayNew(1) />

Emails

Looping backwards over the getEmails query returned by cfpop puts the output in the same order as the inbox with the newest message first. The attachments are stuffed in the arrays using the ListtoArray() function and then looped over to display what and where they are.

           <p><strong>Number of Records:</strong> #getEmail.recordCount#</p>
           <p><strong>FYI - TempDirectory:</strong> #GetTempDirectory()#</p>

      <ul>
         <cfloop from="#getEmail.recordCount#" to="1" step="-1" index="i">

                 <li><strong>Row: #i#</strong><br />
                     <em>MessageNumber:</em> #getEmail.messagenumber[i]#<br />
                     <em>UID:</em> #getEmail.UID[i]#<br />
                     <em>From:</em> #getEmail.From[i]# <br />
                     <em>Subject</em>: #getEmail.Subject[i]#<br />
                     <em>Message:</em> #getEmail.body[i]#<br />

                     <cfif Len(getEmail.attachments[i])>
                        <cfset attachmentNameArray = ListtoArray(getEmail.attachments[i], chr(9)) />
                        <cfset attachmentFileArray = ListtoArray(getEmail.attachmentfiles[i], chr(9)) />

                            <em>Attachments:</em><br />
                            <cfloop from="1" to="#ArrayLen(attachmentNameArray)#" index="num">
                                #attachmentNameArray[num]#<br />
                      		</cfloop>

                             <em>Attachment Files Server Location:</em><br />
                             <cfloop from="1" to="#ArrayLen(attachmentFileArray)#" index="num">
                              #attachmentFileArray[num]#<br />
                            </cfloop>

                     </cfif>
                    </li>

         </cfloop>
      </ul>

SSL off

Turn off SSL and it’s all done. SSL may or may not interfere with other processes on the server. Turning it off helps alleviate that.

<!--- Turn off SSL --->
      <cfset jProps.setProperty("mail.pop3.socketFactory.class", "javax.net.SocketFactory") />

Other Pop-enabled Accounts

This example can be used with other pop-enabled accounts. Try it without SSL first then add that in if needed.

cfpop documentation from Adobe

Complete code file

ColdFusion Brush for SyntaxHighlighter Plus and Evolved

SyntaxHighlighter Plus has been replaced by SyntaxHighligher Evolved. Instructions for adding a ColdFusion brush to both are below.

SyntaxHighlighter Plus is a great WordPress plugin for highlighting code in your blog posts. Out of the box it doesn’t come with a brush for ColdFusion syntax highlighting. A brush is a javascript file that is used by SyntaxHighlighter Plus to determine how to style the code inside the syntax highlighter itself. You could use the HTML brush for ColdFusion code, but a little funkiness happens at times so I added my own brush for ColdFusion.

How to Add the Brush

For Plus and Evolved, add the shBrushColdFusion.js to the scripts folder. If you installed it as a WordPress plugin, the folder structure will be syntaxhighlighter-plus (Plus) or syntaxhighlighter (Evolved), syntaxhighlighter, scripts.
SyntaxHighligher Plus: Modify the syntaxhighlighter.php found in the syntaxhighlighter-plus folder by adding ‘ColdFusion’ => array(‘coldfusion’, ‘cf’), to the aliases array.

$this->aliases = apply_filters( 'agsyntaxhighlighter_aliases', array(
            'Bash'      => array('bash', 'sh', 'shell'),
            'ColdFusion' => array('coldfusion', 'cf'),
            'Cpp'       => array('cpp', 'c', 'c++'),
            'CSharp'  => array('c#', 'c-sharp', 'csharp'),
            'Css'     => array('css'),
            'Delphi'  => array('delphi', 'pascal'),
            'Diff'    => array('diff', 'patch'),
            'Groovy'  => array('groovy'),
            'Java'    => array('java'),
            'JScript' => array('js', 'jscript', 'javascript'),
            'Perl'    => array('perl', 'pl'),
            'Php'     => array('php'),
            'Plain'   => array('', 'plain', 'text'),
            'Python'  => array('py', 'python'),
            'Ruby'    => array('rb', 'ruby', 'rails', 'ror'),
            'Scala'   => array('scala'),
            'Sql'     => array('sql'),
            'Vb'      => array('vb', 'vbnet', 'vb.net'),
            'Xml'     => array('xml', 'html', 'xhtml', 'xslt'),
        ) );

SyntaxHighligher Evolved: Modify the syntaxhighlighter.php found in the syntaxhighlighter folder by adding a registration for the brush in function _construct().

wp_register_script( 'syntaxhighlighter-brush-coldfusion',       plugins_url('syntaxhighlighter/syntaxhighlighter/scripts/shBrushColdFusion.js'),       array('syntaxhighlighter-core'), $this->agshver );

Add ColdFusion to the list of aliases.

'coldfusion'    => 'coldfusion',
'cf'            => 'coldfusion',

How to Use the ColdFusion Brush

Wrap the code you want to display in your post using one of the following methods:

[sourcecode language=’coldfusion’]code here[/sourcecode]
[sourcecode language=’cf’]code here[/sourcecode]
[coldfusion]code here[/coldfusion]
[cf]code here[/cf]

Personally I like the last method the best.


ColdFusion brush javascript code (change extension to .js before uploading)

Google Analytics API Login Authentication with ColdFusion

You might also like the ColdFusion and Google Analytics: Getting Out What You Put In post.

Updated 08-02-2009: Replaced this line:

<cfset accountXML = callApi("https://www.google.com/analytics/feeds/accounts/#urlEncodedFormat(form.Email)#",loginAuth) />

with this:

<cfset accountXML = callApi("https://www.google.com/analytics/feeds/accounts/default",loginAuth) />

My Hooking into Google Analytics with ColdFusion post received a suggestion from Raymond Camden that authentication and token acquisition could be done via cfhttp for access to Google Analytics information. So, here it is again with authentication built in. I set this up with a email/password form but you could easily hard code the email and password in if you so desired.

1. Prompt for email and password of Google account that has access to Google Analytics data. This is an all-in-one example so the form submits back to its own page and processing continues.

<form action="GAwithCFlogin.cfm" method="post">
Google email <input type="text" name="Email" /><br />
Password <input type="password" name="password" /><br />
<input type="submit" />
</form>

2. Authenticate the credentials with Google.

<cfset loginAuth = googleLogin(form.Email,form.password) />

The googleLogin function sends the email/password combo along with the service and source values as URL parameters required by Google to Google’s client login URL via a post request. The source parameter is a Short string identifying your application, for logging purposes. This string should take the form: “companyName-applicationName-versionID” according to Google. You can put in your company name or whatever name you want followed by the rest of the convention Google suggests. Example: yourcompanyname-analytics-1.0. The default start and end dates are also set here.

<!---dates for one full year of stats (default)--->
<cfset startdate = DateFormat(DateAdd("d",-365,CreateDate(Year(Now()),Month(Now()),Day(Now()))), "yyyy-mm-dd") />
<cfset enddate = DateFormat(DateAdd("d", -1, Now()),"yyyy-mm-dd") />

<cffunction name="googleLogin" access="public" returntype="string">
	<cfargument name="email" type="string" required="yes" default="">
	<cfargument name="password" type="string"required="yes" default="">
    <cfargument name="gaLoginUrl" type="string" required="no" default="https://www.google.com/accounts/ClientLogin">

    <cfset var loginAuth = "" />

    <cfhttp url="#arguments.gaLoginUrl#" method="post">
        <cfhttpparam name="accountType" type="url" value="GOOGLE">
        <cfhttpparam name="Email" type="url" value="#arguments.email#">
        <cfhttpparam name="Passwd" type="url" value="#arguments.password#">
        <cfhttpparam name="service" type="url" value="analytics">
        <cfhttpparam name="source" type="url" value="yourCompanyName-analytics-1.0">
    </cfhttp>

	<cfif NOT FindNoCase("Auth=",cfhttp.filecontent)>
		<cfset loginAuth = "Authorization Failed" />
	<cfelse>
		<cfset loginAuth = Mid(cfhttp.filecontent, FindNoCase("Auth=",cfhttp.filecontent) + (Len("Auth=")), Len(cfhttp.filecontent)) />
	</cfif>

    <cfreturn loginAuth />
</cffunction>

What should come back is a long string of authorization token values. There are several but we only need the Auth token. If it’s not in there, we send back “Authorization Failed.” If it’s in there, we strip it out and return it.

3. Get the accounts associated with the email. There can be more than one set up in Analytics.

<cfset accountXML = callApi("https://www.google.com/analytics/feeds/accounts/default",loginAuth) />

The email account is appended onto the Google URL and a get call is made from the callApi function with the loginAuth token attached as a header value.

<cffunction name="callApi" access="public" returntype="string">
    <cfargument name="gaUrl" type="string" required="yes">
    <cfargument name="authToken" type="string" required="yes">

    <cfset var authSubToken = 'GoogleLogin auth=' & arguments.authToken />
    <cfset var responseOutput = "" />

    <cfhttp url="#arguments.gaUrl#" method="get">
        <cfhttpparam name="Authorization" type="header" value="#authSubToken#">
    </cfhttp>

    <cfset responseOutput = cfhttp.filecontent />

    <cfreturn responseOutput />
</cffunction>

The header value must be in the form of Authentication: GoogleLogin auth=DF3843483…(it’s kind of long but you get the idea). This authentication is different form AuthSub Proxy authentication used in my previous post.

4. Clean up the XML that returned so we can use XmlSearch() and other handy functions available in ColdFusion. For some reason the atom specification of the XML file bungles those functions up. We need to remove the xmlns nodes from the feed element and remove the dxp prefixes. Do a cfdump on the XML before and after two lines of code used to tidy them up to seed what happens.

<cfdump var="#accountXML#">

Then roll through the accountXML with to grab all the profiles and toss them into an array so we can loop through them later.

<!---remove dxp: prefix from nodes that have it--->
	<cfset accountXML = accountXML.ReplaceAll("(</?)(\w+:)","$1") />
	<!---Strip xmlns from feed element--->
	<cfset accountXML = REReplaceNoCase(accountXML,"<feed[^>]*>","<feed>") />

	<cfset entryNodes = XmlSearch(accountXML, '//entry/') />

	<cfset profileArray = ArrayNew(1) />

	<cfloop from="1" to="#ArrayLen(entryNodes)#" index="num">
		<cfset entryStruct = StructNew() />

		<cfset entryStruct.id = entryNodes[num].id.XmlText />
		<cfset entryStruct.title = entryNodes[num].title.XmlText />
		<cfset entryStruct.tableId = entryNodes[num].tableId.XmlText />

		<cfloop from="1" to="#ArrayLen(entryNodes[num].property)#" index="i">
   			<cfswitch expression='#entryNodes[num].property[i].XmlAttributes["name"]#'>
    		    <cfcase value="ga:accountId">
       		     <cfset entryStruct.accountId = entryNodes[num].property[i].XmlAttributes["value"] />
     		   </cfcase>
      		  <cfcase value="ga:accountName">
    		        <cfset entryStruct.accountName = entryNodes[num].property[i].XmlAttributes["value"] />
 		       </cfcase>
		         <cfcase value="ga:profileId">
		               <cfset entryStruct.profileId = entryNodes[num].property[i].XmlAttributes["value"] />
	            </cfcase>
	            <cfcase value="ga:webPropertyId">
	                <cfset entryStruct.webPropertyId = entryNodes[num].property[i].XmlAttributes["value"] />
	            </cfcase>
	        </cfswitch>
	    </cfloop>

		    <cfset arrayAppend(profileArray,duplicate(entryStruct)) />

		</cfloop>

5. Loop through the profiles, grab the page views and visitors, and tally them up for all profiles.

<cfset totalpageviews = 0 />
<cfset totalvisitors = 0 />

		<cfloop from="1" to="#ArrayLen(profileArray)#" index="num">
	    	<cfset reqUrl = "https://www.google.com/analytics/feeds/data?ids=" & profileArray[num].tableId & "&metrics=ga:pageviews,ga:visitors&start-date=" & startdate & "&end-date=" & enddate />

	 		 <cfset statsXML = callApi(reqUrl,loginAuth) />
	                <!---Tidy up the XML again --->
	 		 <cfset statsXML = statsXML.ReplaceAll("(</?)(\w+:)","$1") />
			 <cfset statsXML = REReplaceNoCase(statsXML,"<feed[^>]*>","<feed>") />

			 <cfset metric = XmlSearch(statsXML, '//metric/') />

			 <cfset pageviews = metric[1].XmlAttributes["value"] />

                         <cfset visitors = metric[2].XmlAttributes["value"] />

			 <cfset totalpageviews = totalpageviews + pageviews />

                         <cfset totalvisitors = totalvisitors + visitors />

			 <p><strong>Profile:</strong> <em>#profileArray[num].title#</em> Pageviews: #NumberFormat(pageviews, ",")# Visitors: #NumberFormat(visitors, ",")# </p>

		 </cfloop>

		<p><strong>Total pageviews:</strong> #NumberFormat(totalpageviews, ",")#</p>
                <p><strong>Total visitors:</strong> #NumberFormat(totalvisitors, ",")#</p>

All done. Thank you Raymond Camden and Alex Curelea. Alex got me pointed in the right direction with his post Using the Google Analytics API – getting total number of page views. And, as I mentioned at the get go, Raymond Camden made the suggestion of using the login as some of his examples have done in the past.

Recommended Reading

Download

Information on Google’s Authentication for Installed Application ClientLogin and the Google Analytics Data API ClientLogin Username/Password Authentication.

Helpful ColdFusion books include the all-in-one ColdFusion MX 7 WACK with tons of good information even if you’ve moved up to CF8. Crazy as it seems, Adobe decided to break up ColdFusion 8 books into three volumes: Volume 1: Getting Started, Volume 2: Application Development, and Volume 3: Advanced Application Development. You may be able to pick up a used copy in good condition. Follow the book link to Amazon and look for used copies underneath the books title.

Hooking into Google Analytics with ColdFusion

You might also like the ColdFusion and Google Analytics: Getting Out What You Put In post.

Using Alex Curelea’s example of using PHP to hook into Google Analytics through their API, I developed a ColdFusion method. So, same thing as Alex just flavored with CF. The code grabs the profiles and pageviews, then totals up the pageviews for all profiles.

Update: I followed Raymond Camden’s suggestion below and posted another version of this using ClientLogin Authentication.

1. Authenticate user and get token from Google. Basically just a link that sends them off to Google and Google returns them to your page designated in the href with token attached as URL param.

<a href="https://www.google.com/accounts/AuthSubRequest?next=http://www.your-site-here.com/GAwithCF.cfm&scope=https://www.google.com/analytics/feeds/
&secure=0&session=1">Authenticate through Google.</a>

2. Send that token back to Google and get a session token that can be used to retrieve the profile information and data. This is handled in two functions that I originally had in a CFC. I put all the code on one page for this example.

For the session token required for access to the data, the sessionToken function is called with the URL.token passed in.

<cfset authSessionToken = sessionToken(URL.token) />

The sessionToken function makes a get request to https://www.google.com/accounts/AuthSubSessionToken with the token as a header value using the callApi function. The header value must be in the form of Authorization: AuthSub token=”C8b_xxxxxxxxx” with the token equaling the URL.token.
The session token comes back in the form of “Token=CH____88dfdsfsd.” Strip off the “Token=” and you have your session token. The default start and end dates are also set here.

<!---dates for one full year of stats (default)--->
<cfset startdate = DateFormat(DateAdd("d",-365,CreateDate(Year(Now()),Month(Now()),Day(Now()))), "yyyy-mm-dd") />
<cfset enddate = DateFormat(DateAdd("d", -1, Now()),"yyyy-mm-dd") />

<cffunction name="sessionToken" access="public" returntype="string">
	<cfargument name="authToken" type="string" required="yes">

    <cfset var output = callApi("https://www.google.com/accounts/AuthSubSessionToken",arguments.authToken) />
    <cfset var authSubSessionToken = "" />

    <cfset authSubSessionToken = Mid(output, FindNoCase("Token=",output) + (Len("Token=")), Len(output)) />

    <cfreturn authSubSessionToken />
</cffunction>

<cffunction name="callApi" access="public" returntype="string">
    <cfargument name="gaUrl" type="string" required="yes">
    <cfargument name="authToken" type="string" required="yes">

    <cfset var authSubToken = 'AuthSub token="' & arguments.authToken & '"' />
    <cfset var responseOutput = "" />

    <cfhttp url="#arguments.gaUrl#" method="get">
        <cfhttpparam name="Authorization" type="header" value="#authSubToken#">
    </cfhttp>

    <cfset responseOutput = cfhttp.filecontent />

    <cfreturn responseOutput />
</cffunction>

3. Now the callApi function can be used with the authSessionToken to return the account profiles as XML. Unfortunately, it’s an atom feed XML so a little stripping must occur before we can use the handy XMLSearch function in ColdFusion.

<cfset accountXML = callApi("https://www.google.com/analytics/feeds/accounts/default",authSessionToken) />

First we remove the nodes with a dxp: prefix. Then we clear the “xmlns” nodes in the feed element. That’s what bugs up XMLSearch.

<cfset accountXML = accountXML.ReplaceAll("(</?)(\w+:)","$1") />
<cfset accountXML = REReplaceNoCase(accountXML,"<feed[^>]*>","<feed>") />

Anytime you want to take a peek at the XML, you can use cfdump to spit it out for you.

<cfdump var="#XMLParse(accountXML)#">

4. Parse out the XML to put the profiles in an array for easy looping later.

<cfset entryNodes = XmlSearch(accountXML, '//entry/') />

<cfset profileArray = ArrayNew(1) />

<cfloop from="1" to="#ArrayLen(entryNodes)#" index="num">
    <cfset entryStruct = StructNew() />

    <cfset entryStruct.id = entryNodes[num].id.XmlText />
    <cfset entryStruct.title = entryNodes[num].title.XmlText />
    <cfset entryStruct.tableId = entryNodes[num].tableId.XmlText />

    <cfloop from="1" to="#ArrayLen(entryNodes[num].property)#" index="i">
        <cfswitch expression='#entryNodes[num].property[i].XmlAttributes["name"]#'>
            <cfcase value="ga:accountId">
                <cfset entryStruct.accountId = entryNodes[num].property[i].XmlAttributes["value"] />
            </cfcase>
            <cfcase value="ga:accountName">
                <cfset entryStruct.accountName = entryNodes[num].property[i].XmlAttributes["value"] />
            </cfcase>
            <cfcase value="ga:profileId">
                <cfset entryStruct.profileId = entryNodes[num].property[i].XmlAttributes["value"] />
            </cfcase>
            <cfcase value="ga:webPropertyId">
                <cfset entryStruct.webPropertyId = entryNodes[num].property[i].XmlAttributes["value"] />
            </cfcase>
        </cfswitch>
    </cfloop>

    <cfset arrayAppend(profileArray,duplicate(entryStruct)) />

</cfloop>

5. Loop through each profile, grab the metrics you want for each profile from Google, display them on the page, and tally up the total page views count. The XML needs some tidying again but you saw that earlier.

<cfset totalpageviews = 0 />

<cfloop from="1" to="#ArrayLen(profileArray)#" index="num">
    <cfset reqUrl = "https://www.google.com/analytics/feeds/data?ids=" & profileArray[num].tableId & "&metrics=ga:pageviews&start-date=" & startdate & "&end-date=" & enddate />

    <cfset statsXML = callApi(reqUrl,authSessionToken) />
    <!---Tidy up the XML--->
    <cfset statsXML = statsXML.ReplaceAll("(</?)(\w+:)","$1") />
    <cfset statsXML = REReplaceNoCase(statsXML,"<feed[^>]*>","<feed>") />

<cfset metric = XmlSearch(statsXML, '//metric/') />

<cfset pageviews = metric[1].XmlAttributes["value"] />

<cfset totalpageviews = totalpageviews + pageviews />

<p>Profile: #profileArray[num].title# #NumberFormat(pageviews, ",")#</p>

</cfloop>

<p>Total pageviews: #NumberFormat(totalpageviews, ",")#</p>

That’s it. It should at least get you started. Thanks Alex!

Recommended Reading

Download

News of the Google Analytics API

Information on Google AuthSub Proxy Authentication.

Helpful ColdFusion books include the all-in-one ColdFusion MX 7 WACK with tons of good information even if you’ve moved up to CF8. Crazy as it seems, Adobe decided to break up ColdFusion 8 books into three volumes: Volume 1: Getting Started, Volume 2: Application Development, and Volume 3: Advanced Application Development. You may be able to pick up a used copy in good condition. Follow the book’s link above to Amazon and look for used copies underneath the books title.