It’s actually very easy to retrieve POP emails using the cfpop tag as we can see from the tag’s reference on Macromedia. This tag is capable of returning all the headers that were sent along with the email. However, the headers are usually all cramped together in one long string. We might run into a situation where we want to get specific name-value pairs, like for example the value of Reply-To, and so we’ll see how to do that.
Getting the email headers
We can do this in two ways:
- Using the GetAll option in the tag
- Using the GetHeaderOnly option (default)
Let’s work with the GetAll option. Calling the tag should look something like this:
<cfpop server="mail.youremailserver.com" username="email@example.com" password="yourpassword" action="GetAll" name="qMail">
What we get back is a query whose name we have assigned as qMail. Using the GetAll option in this tag actually requires that you assign a name to the returned query, just like we have done. The headers are stored inside the returned query in a variable called simply headers. So let’s loop through all the returned email headers:
<cfoutput> <cfloop query="qMail"> #qMail.header# <hr> </cfloop> </cfoutput>
And the results from the browser:
As you can see, each email header looks like a long string and it’s not that easy to get a specific value.
Searching for a specific name in the header
Each name-value pair is actually separated by a line break. Knowing this, we can create a function that will search for a specific name inside this string and get its value.
<cffunction name="GetHeaderValue" access="public" output="false" returntype="string"> <cfargument name="aHeader" required="yes" type="string"> <cfargument name="aHeaderName" required="yes" type="string"> <cfset var arrHeaderValues = ArrayNew(1)> <cfset var cHeaderValue = ""> <cfset arrHeaderValues = ListToArray(arguments.aHeader, chr(10))> <cfloop from="1" to="#ArrayLen(arrHeaderValues)#" index="value"> <cfif Left(arrHeaderValues[value], Len(arguments.aHeaderName)) IS arguments.aHeaderName> <cfset cHeaderValue = Mid(arrHeaderValues[value], Len(arguments.aHeaderName) + 3, Len(arrHeaderValues[value]))> <cfbreak> </cfif> </cfloop> <cfreturn cHeaderValue> </cffunction>
The function accepts two arguments: the whole header text and the name of the header that we want to get (e.g. From, To, etc.). When passing in the name of header, lettercase does not really matter. First it creates an array of elements based on the line breaks it finds (i.e. chr(10)). Then it loops through this array and tries to find the name that you are looking for by matching the beginning of each array element to the actual name. Once it finds it, it simply gets its value, breaks out of the loop and returns it.
So, for example to get the value of Content-Type we can call this function like so:
<cfoutput> <cfloop query="qMail"> #GetHeaderValue(qMail.header, "Content-Type")# <hr> </cfloop> </cfoutput>
Running this code now will display the content type of each email:
We have seen how to retrieve email headers using the cfpop tag and then how to break them up to retrieve specific values. This is a relatively simple solution and there are some potential issues with this that I will leave up to the reader to pick up from here. For example:
- Some emails could have a specific header declared more than once inside the header. My function will return the first occurence.
- Some header values may span over several lines, e.g. Received. My function will return the first line only.