[unspecified] Thursday, May 08 2008
How do I do my auto-email stuff? Well, if you have your site set up like I do and you think about it for a while, then really it's pretty easy. But since you don't have your site set up like mine I'll give you a relatively quick rundown.
- All of my pages are using XML. Blogger writes XML files to my server, and I use ASP to transform the XML into HTML (using the Microsoft XML Parser 2 and XSLT). That allows me to separate all content from the display, to allow me to do anything with the content I want (multiple layouts, WML pages, content emailing, etc). The xml template is pretty easy, here is my blogger XML template:
<xblog> <blog> <Blogger> <BlogDateHeader> <day date="<$BlogDateHeaderDate$>"> </BlogDateHeader> <body> <item><$BlogItemNumber$></item> <time><$BlogItemDateTime$></time> <author><$BlogItemAuthor$></author> <email><$BlogItemAuthorEmail$></email> <archiveFile><$BlogItemArchiveFileName$></archiveFile> <text><![CDATA[<$BlogItemBody$>]]></text> </body> <BlogDateFooter> </day> </BlogDateFooter> </Blogger> </blog> </xblog>What this gives me is a simple xml tag-only (no attributes) document that contains nodes for the item number (a unique value), time, author, author email, archive file, and the actual content itself. With this I can do pretty much anything from automatically emailing content to parsing the XML tree to get whatever data I feel is relevant for a specific section.
- The next step, now that we have a simple XML document to work with, is to figure out how and when content gets emailed. Since I don't have administrative control over my server I cannot create a simple VB .dll that would handle everything for me. Just set it on a timer and let it go. That would be very easy but unfortunately I couldn't do that, so the only other option I had was to let my users do my work for me. What does that mean? Well, it's pretty simple really. Instead of using a timer I based it off of every 'X'-th hit to my page I have a script run that checks for new content. I have two methods of keeping track of page hits. The most simple one is an Application variable I increment with every page hit. When "Application("page_counter") Mod 5 = 0" evaluates to true, I check for new content. The other thing I do is every time my script finds that there is new content, it writes the value of the ITEM tag above to a simple text file. I do this in case the Application restarts and I lose the Application-level variable.
- Now that we've decided when to check for new content, the next step is to actually do the checking. Again it's pretty simple. Since I have a simple XML document opened, what I do is parse it using the MSXML2 parser and look for every node that matches this pattern: "xblog/blog/day/body".
<% Dim xmlDoc Set xmlDoc = Server.CreateObject("Microsoft.XMLDOM") xmlDoc.async = false xmlDoc.load Server.MapPath("/surreal/blog/blogger.xml") Dim bodyList Set bodyList = xmlDoc.getElementsByTagName("xblog/blog/day/body") %>What this gives me is a "hot" list of body tags in my XML document. By hot I mean each element in the list is a pointer to a location in the real XML object rather than an in-memory copy. Okay now that I have a list of body tags I need to run through it and find the "oldest newest" element. By "oldest newest" I mean the most recent item immediately after the saved most recent item. Basically since the newer the item is the closer to the top of the physical document it will be. So all you need to do is go through each element and do a simple test: "Is the current element greater than the saved element?" If the answer is yes, you set a return value equal to the current element. But you do not return, you continue the loop until it's done. Here is the code:<script language="javascript" runat="server"> function getNewestItem(){ var oldestNewest = 0; var xmlDoc = Server.CreateObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.load(Server.MapPath("/surreal/blog/blogger.xml")); var list = xmlDoc.getElementsByTagName("xblog/blog/day/body"); for(x = 0; x < list.length; x++){ oldestNewest = parseInt(list.item(x).childNodes(0).text); if(parseInt(list.item(x).childNodes(0).text) > Application("Blog.NewestItem")){ oldestNewest = parseInt(list.item(x).childNodes(0).text); } } xmlDoc = null; list = null; if(oldestNewest != 0) return oldestNewest; else return 0; } </script>Yes, this function is in javascript. I frequently mix my VBScript and JavaScript in ASP quite simply because I like how JavaScript handles strings and numbers better than VBScript.
- Okay, now we have the "oldest newest" item, we need to get the all the content that is new. Once again get a list of the "xblog/blog/day/body" tags. Then we loop through the list and grab the content of the nodes from any body tag that has an item tag value greater than our "oldest newest" item. If we encounter an item that is less than or equal to then we'll return from the function and just go with what we've got. Here is the code:
<script language="javascript" runat="server"> function getNewestContent(){ var xmlDoc = Server.CreateObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.load(Server.MapPath("/surreal/blog/blogger.xml")); var list = xmlDoc.getElementsByTagName("xblog/blog/day/body"); var sReturn = ""; for(x = 0; x < list.length; x++){ if(parseInt(list.item(x).childNodes(0).text) <= Application("Blog.NewestItem")) return sReturn; sReturn += "\n\n"+ list.item(x).childNodes(1).text; sReturn += "\n"+ list.item(x).childNodes(2).text + " (" + list.item(x).childNodes(3).text + ")" sReturn += "\n\n"+ list.item(x).childNodes(5).text; } xmlDoc = null; list = null; return sReturn; } </script>
- There that was easy. Now all I have to do is open up my simple little access database, get everyone's email who has subscribed and verified their email address and create a CDONTS.NewMail object, set the .To to my address and BCC everyone else. Next I send the mail.
- The last step is to save the newest item into the Application variable and save it to file. You could possibly do a lot more with this simple setup. You could let users subscribe to HTML or Plain Text emails, and I'm sure there's more but I'm done thinking. I do a little bit more; I log everything so every time there have been 5 page hits I log parts of the code then write it to file so I can see if there are any performance issues with all the code I've written.
Okay there ya go. A setup for a very eXtensible website and basic instructions on how to create an auto content email system. Interested in me writing anything else? Let me know and I'll probably be more than happy to write it up.

