Edit 2/20/2013: Be sure to see Karl's comment! I got an interesting question earlier this week. A reader was using cfpop to retrieve email information. They had built a paging system by using getHeadersOnly. This returns a 'slimmer' query where email bodies are not included in the result. He then paged through the query and fetched the bodies 10 at a time. (Do I need to demo that? Let me know and I'll do another blog entry.) This worked fine until the email account got overloaded. Eventually even the "quicker" getHeadersOnly operation was taking forever. He ask - is there some way to get just the total number of messages in a mailbox?
I double checked the documentation for cfpop and didn't see any particular support for this operation. On a whim I tried the following:
<cfpop server="Mail.colts.com" action="getHeaderOnly" username="raycamden@colts.com" password="icodephpinthecloset" name="mail"
maxrows=1 startrow=999
>
This returned:
The start row 999 is greater than the total number of messages 5.
So cfpop definitely was able to get the total number of messages, but I saw no way to get that myself. I could have wrapped the call in a try/catch and parsed the error, but that just felt dirty to me.
I did some digging into the javax.mail package which ColdFusion uses under the hood for it's mail support. It was a bit confusing at first, but this article helped a bit and formed the basis for my code. Basically, POP support entails creating a Mail Session (not the same as a ColdFusion session!), a mail store, and finally grabbing the inbox folder. The Folder object contains a method that returns a message count. It took me a good hour or two to figure this out (boy do I appreciate how easy ColdFusion makes things!) but I was able to get it down to a few lines of code:
<cfset props = createObject("java","java.lang.System").getProperties()>
<cfset msession = createObject("java", "javax.mail.Session")>
<cfset m2 = msession.getDefaultInstance(props)>
<cfset store = m2.getStore("pop3")>
<cfset store.connect("Mail.colts.com","raycamden@colts.com","isecretlywritephp")>
<cfset df = store.getFolder("INBOX")>
<cfset df.open(df.READ_ONLY)>
<cfdump var="#df.getMessageCount()#">
The main line you would care about is the connet operation. Note the server, username, and password (yes, it's fake). The df variable is my folder object. You can do more with it then just getting a count obviously, but actually getting mail would be simpler with cfpop. If you actually used this in production you would probably want to turn it into a UDF.
Archived Comments
Very interesting! Thx. Maybe there is also a way to see if an email has an attachment without getting the full body information.
Best,
Michi
You can do it using IMAP as well, not sure who to credit for this code: http://rafb.net/p/IX15UV86....
@Ray
This was an interesting read but I have one question. Does the getMessageCount() method take into consideration the number of messages held in nested subfolders within the folder that you're doing the count on? So for instance if I have an e-mail folder named clients and then underneath that I have a folder for each client but I want the count of total client e-mails does the method provide recursion?
I can't figure this out by reading Sun's docs so I'll probably just have to test it sometime.
There is a HOLDS_FOLDERS attribute (constant field) which can be summoned to figure out if a folder can hold other folders but I've never tried to use it.
Just curious - thanks for the cool post!
I have no idea Andy. I'd love it if someone could test with a subfolder. I'd also be curious to see if cfpop would return the subfolder contents. If not, it doesn't matter. It was my impression cfpop was just getting the root folder.
I have a mail type project coming up so I'll make a note to share my java mail api findings with the rest of the group (I just love littering your blog ya know).
Can't the reader use the "recordcount" to get the total number of messages in a mailbox as the following?
<CFPOP server="Mail.colts.com"
action="getHeaderOnly"
username="raycamden@colts.com"
password="icodephpinthecloset"
name="mail">
<CFSET Totalcount = mail.recordcount/>
Mamdoh, please reread the entry a bit closer. Yes, he can, but the process of getting the headers was taking too long. If you do maxrows=10, the recordcount will be 10, not the 'real' count on the mail server.
I've used a process very similar to what was first mentioned in order to get the number of unread messages in a mail account. Same problem... if the user's inbox is overloaded with messages, it takes way too long to get the count. Using your method, could you get the number of unread/new messages?
Yep, it's one more method in the Folder object:
http://java.sun.com/product...
No joy. getUnreadMessageCount() gives me the number of total messages and getNewMessageCount() gives me zero. Perhaps this does not work with our version of iMail.
An old thread, I know, but I found it very useful today, except for one thing: you have to close off the mail session, or else any subsequent cfpop attempts won't work! The link to the java article is dead (shouldn't a UNIVERSAL record locator be forever?), but I found what I needed somewhere else (and yes, once you know it's duh obvious -- isn't hindsight great?); put this at the end of the above code:
<cfset df.close(false)>
Thank you for sharing that Karl. I felt your comment was important enough for me to update the entry to point it out.
Of course It will work, but It will only work when you're fetching all the email from the inbox. What if you're fetching only 30 emails.? Well mail.recordcount will return 30 only.
Shouldn't you close everything?
<cfset df.close(true)="">
<cfset store.close()="">
Karl's comment mentions closing df, but that wouldn't hurt too.