| 
 | 
	
 
 
                        90%使用WebDAV开发的Exchange邮件管理(三)  
                                                                                            ——获取邮件  
 
        这段时间在做项目的用户培训,闲下来的工夫抱着三本书乱啃一通:《C# Primer Plus》,用来反复巩固OO的概念和基础,《JAVA与模式》,既是对模式的学习,也是对OO的深入。还有就是《.net 框架程序设计》。感觉收获不小,但时间越往后,对这个项目里的一些技术细节和内容遗忘得越快。前几天去蓝凌面试,填完表后就做题,连win1=window.open('herf','name','')这样的JS都写错了,回来才想起来,但当时大脑就是一片混沌。所以决定尽快将这部分的个人知识管理工作做完。这段时间,在.net开发群里也有人问到这些相关的,不过我还没写出来,没能帮到别人,真是惭愧。  
 
一、用Search方法获取邮件列表。  
        如上一篇所讲,首先定义要查询的URL:  
 
string strRootURI = "http://191.0.0.111/exchange/"+userID.Trim()+"/收件箱/";         然后,生成发送查询请求的XML:  
 
// Build the SQL query.  
                strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >"  
                    + "<D:sql>SELECT \"urn:schemas:httpmail:importance\",\"urn:schemas:httpmail:from\",\"urn:schemas:httpmail:read\",\"urn:schemas:httpmail:datereceived\",\"urn:schemas:httpmail:subject\",\"urn:schemas:httpmail:hasattachment\","  
                    +"\"DAV:contentclass\",\"DAV:getcontentlength\",\"DAV:displayname\""  
                    + "FROM \""    + strRootURI + "\""  
                    + "WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"  
                    + "</D:sql></D:searchrequest>"; 最后,解析查询返回的XML文档,得到各项内容:  
 
// Get the XML response stream.  
                ResponseStream = Response.GetResponseStream();  
                  
                // Create the XmlDocument object from the XML response stream.  
                ResponseXmlDoc = new XmlDocument();  
                ResponseXmlDoc.Load(ResponseStream);  
              
                // Build a list of the DAV:href XML nodes, corresponding to the folders  
                // in the mailbox.  The DAV: namespace is typically assgigned the a:  
                // prefix in the XML response body.  
                XmlNodeList idNodes=ResponseXmlDoc.GetElementsByTagName("a:displayname");  
                XmlNodeList SenderNodes = ResponseXmlDoc.GetElementsByTagName("d:from");  
                XmlNodeList importanceNodes=ResponseXmlDoc.GetElementsByTagName("d:importance");  
                XmlNodeList contextclassNodes=ResponseXmlDoc.GetElementsByTagName("a:contentclass");  
                XmlNodeList    readNodes=ResponseXmlDoc.GetElementsByTagName("d:read");  
                XmlNodeList    datareceiveNodes=ResponseXmlDoc.GetElementsByTagName("d:datereceived");  
                XmlNodeList subjectNodes=ResponseXmlDoc.GetElementsByTagName("d:subject");  
                XmlNodeList getcontentlengthNodes=ResponseXmlDoc.GetElementsByTagName("a:getcontentlength");  
                XmlNodeList    hasattachmentNodes=ResponseXmlDoc.GetElementsByTagName("d:hasattachment");             然后通过将得到的属性添加到DataTable,绑定到DataGrid上。 
 
 
        这里要注意的是:虽然邮件是以邮件主题来命名,但相同的邮件主题,其displayname是不一致的,而这个我个人认为也应该是其在WWS中唯一的标志符。如图中的前两封邮件,subject都是ffffffff,但displayname分别为fffffffff.EML和fffffffff-1.EML。 
        另外就是DataGrid上重要性和是否已读等的图片绑定,这个可能对初学者比较有用。当时因时间仓促,我是这样来做的: 
 
<asp:Label id=Label1 runat="server" Text='<%# DataBinder.Eval(Container, "DataItem.importance").ToString()=="1"?"":"<img src=\"images/prio"+DataBinder.Eval(Container, "DataItem.importance")+".gif\">" %>'>将图片的名字分别与重要性的标识位相对应。默认不显示,如果重要性为2,则显示的图片就是prio2.gif。 
 
二、用PROPFIND方法得到某邮件的具体属性  
        在上述的内容中,我们得到了邮件列表的DataGrid,接着就要通过邮件的displayname,来获取邮件的具体属性。基本方式还是如上。这里用来显示邮件内容的地方用到了一点JS的东东,至于实现上,应该是和EXCHANGE一样的。效果如图:
 
 
首先在页面中放了一个IFrame,IFrame中引用的blank.htm为完全空白文件,下面放了一个隐藏的TextArea,将其设为服务器端组件,html代码如下: 
 
<IFRAME class="ipFlat" id="idHtmlBody" name="idHtmlBody" src="blank.htm" frameBorder="0" 
                                                    width="100%" height="100%" security="restricted"></IFRAME><TEXTAREA id="idBody" style="DISPLAY: none" runat="server"></TEXTAREA>在程序中获取邮件的正文信息: 
 
XmlNodeList htmldescription=ResponseXmlDoc.GetElementsByTagName("e:htmldescription"); 
this.idBody.InnerHtml=htmldescription[0].InnerText;最后是页面中的JAVASCRIPT:  
        <script language="JavaScript"> 
function window.onload() 
 
 
 
{ 
 
var oFrm = document.frames["idHtmlBody"]; 
g_winDocAll = window.document.all; 
oFrm.document.write(g_winDocAll.idBody.value); 
oFrm.document.close(); 
 
} 
        </script> 
三、用X-MS-ENUMATTS方法获取附件名称及属性 
        X-MS-ENUMATTS据说是微软以前未公布的方法,这次在Exchange2003里面才公布出来的。但我用的时候,还是发现一些小问题。这里的问题是当我用PR_ATTACH_FILENAME_W得到附件的名称时,发现文件名只能显示8个字符,简直晕死,恍惚回到了DOS时代(偶没学过dos,但考计算机三级的时候学到开始是不支持长文件名的)。不过还好可以得到附件的路径。还是在附件路径上作分拆字符串吧。  
    Response = (HttpWebResponse)Request.GetResponse(); 
 
                // Get the XML response stream. 
                ResponseStream = Response.GetResponseStream(); 
 
                // Create the XmlDocument object from the XML response stream. 
                ResponseXmlDoc = new System.Xml.XmlDocument(); 
 
                // Load the XML response stream. 
                ResponseXmlDoc.Load(ResponseStream); 
 
                // Get the root node. 
                root = ResponseXmlDoc.DocumentElement; 
 
                // Create a new XmlNamespaceManager. 
                nsmgr = new System.Xml.XmlNamespaceManager(ResponseXmlDoc.NameTable); 
 
                // Add the DAV: namespace, which is typically assigned the a: prefix 
                // in the XML response body.  The namespaceses and their associated 
                // prefixes are listed in the attributes of the DAV:multistatus node 
                // of the XML response. 
                nsmgr.AddNamespace("a", "DAV:"); 
 
                // Add the http://schemas.microsoft.com/mapi/proptag/ namespace, which 
                // is typically assigned the d: prefix in the XML response body. 
                nsmgr.AddNamespace("d", "http://schemas.microsoft.com/mapi/proptag/"); 
 
                // Use an XPath query to build a list of the DAV:propstat XML nodes, 
                // corresponding to the returned status and properties of 
                // the file attachment(s). 
                PropstatNodes = root.SelectNodes("//a:propstat", nsmgr); 
 
                // Use an XPath query to build a list of the DAV:href nodes, 
                // corresponding to the URIs of the attachement(s) on the message. 
                // For each DAV:href node in the XML response, there is an 
                // associated DAV:propstat node. 
                HrefNodes = root.SelectNodes("//a:href", nsmgr);  然而,此时通过HrefNodes.InnerText得到的却是形如http://191.0.0.111/exchange/zhouhongying/%E6%94%B6%E4%BB%B6%E7%AE%B1/No%20Subject-7.EML/%E6%A0%B7%E5%93%81.jpg的字符串,也就说中文字符被转换成了UTF8的编码,详细参考见《IIS如何接收ServerXMLHTTP传过来的编码字符》(原作者不详)。那么将分拆的字符串进行码制转换即可。 
 
int index=HrefNodes.InnerText.LastIndexOf('/')+1; 
                            string attachmentName=HrefNodes.InnerText.Substring(index);                             
                            int    mLastIndex=attachmentName.LastIndexOf('.'); 
                            string mMainName=attachmentName.Substring(0,mLastIndex); 
                            mMainName=Server.UrlDecode(mMainName); 
                            int mExtLength=attachmentName.Length - mLastIndex; 
                            string mExtName= attachmentName.Substring(mLastIndex,mExtLength);                 
                            this.LAttachment.Text+="<a href=\"MailAttachment/"+displayname+"/"+mMainName+"."+mExtName+"\" target=\"_blank\">"+mMainName+"."+mExtName+"("+size+")</a>    "; 
                            _attachmentName=mMainName+"."+mExtName; 
附录代码: 
 
private void GetDateToForm(string displayname) 
        { 
            System.Net.HttpWebRequest Request; 
            System.Net.WebResponse Response; 
            System.Net.CredentialCache MyCredentialCache; 
//            string strSrcURI = "http://191.0.0.111/exchange/administrator/收件箱/"+displayname; 
//            string strUserName = "administrator"; 
 
            string userID=User.Identity.Name.Trim(); 
            string strSrcURI = "http://191.0.0.111/exchange/"+userID+"/收件箱/"+displayname; 
            string strUserName = userID; 
 
            //string strPassword = "afineday"; 
            string strPassword=DAL.Data.UserModel.SelectByUserId(userID).Password.Trim(); 
            string strDomain = "oa.lgyw"; 
            string strBody = ""; 
            byte[] bytes = null; 
            System.IO.Stream RequestStream = null; 
            System.IO.Stream ResponseStream = null; 
            XmlDocument ResponseXmlDoc = null; 
             
            try 
 
 
            { 
                // Build the PROPFIND request body. 
                //            strBody = "<?xml version=\"1.0\"?>" 
                //                + "<d:propfind xmlns:d='DAV:'><d:prop>" 
                //                + "<d:displayname/></d:prop></d:propfind>"; 
                strBody="<?xml version=\"1.0\"?>" 
                    + "<d:propfind xmlns:d='DAV:'><d:allprop/>" 
                    +"</d:propfind>"; 
                // Create a new CredentialCache object and fill it with the network 
                // credentials required to access the server. 
                MyCredentialCache = new System.Net.CredentialCache(); 
                MyCredentialCache.Add( new System.Uri(strSrcURI), 
                    "NTLM", 
                    new System.Net.NetworkCredential(strUserName, strPassword, strDomain) 
                    ); 
 
                // Create the HttpWebRequest object. 
                Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strSrcURI); 
 
                // Add the network credentials to the request. 
                Request.Credentials = MyCredentialCache; 
 
                // Specify the method. 
                Request.Method = "PROPFIND"; 
 
                // Encode the body using UTF-8. 
                bytes = Encoding.UTF8.GetBytes((string)strBody); 
 
                // Set the content header length.  This must be 
                // done before writing data to the request stream. 
                Request.ContentLength = bytes.Length; 
 
                // Get a reference to the request stream. 
                RequestStream = Request.GetRequestStream(); 
 
                // Write the request body to the request stream. 
                RequestStream.Write(bytes, 0, bytes.Length); 
 
                // Close the Stream object to release the connection 
                // for further use. 
                RequestStream.Close(); 
 
                // Set the content type header. 
                Request.ContentType = "text/xml"; 
 
                // Send the PROPFIND method request and get the 
                // response from the server. 
                Response = (HttpWebResponse)Request.GetResponse(); 
 
                // Get the XML response stream. 
                ResponseStream = Response.GetResponseStream(); 
                // Create the XmlDocument object from the XML response stream. 
                ResponseXmlDoc = new XmlDocument(); 
                ResponseXmlDoc.Load(ResponseStream); 
             
                // Build a list of the DAV:href XML nodes, corresponding to the folders 
                // in the mailbox.  The DAV: namespace is typically assgigned the a: 
                // prefix in the XML response body.             
                XmlNodeList SenderNodes = ResponseXmlDoc.GetElementsByTagName("e:from"); 
                XmlNodeList ToNodes=ResponseXmlDoc.GetElementsByTagName("e:to"); 
                XmlNodeList CCNodes=ResponseXmlDoc.GetElementsByTagName("d:cc"); 
                XmlNodeList importanceNodes=ResponseXmlDoc.GetElementsByTagName("e:importance");         
                XmlNodeList sensitivityNodes=ResponseXmlDoc.GetElementsByTagName("d:sensitivity"); 
                XmlNodeList    datareceiveNodes=ResponseXmlDoc.GetElementsByTagName("e:datereceived"); 
                XmlNodeList subjectNodes=ResponseXmlDoc.GetElementsByTagName("e:subject"); 
                XmlNodeList htmldescription=ResponseXmlDoc.GetElementsByTagName("e:htmldescription");             
                XmlNodeList    hasattachmentNodes=ResponseXmlDoc.GetElementsByTagName("e:hasattachment");         
                if(subjectNodes.Count > 0) 
                { 
                    this.Lfrom.Text=SenderNodes[0].InnerText.Replace("<","<").Replace(">",">"); 
                    this.Ldatareceived.Text=DateTime.Parse(datareceiveNodes[0].InnerText).ToString(); 
                    this.Lreceive.Text=ToNodes[0].InnerText.Replace("<","<").Replace(">",">"); 
                    this.LSubject.Text=subjectNodes[0].InnerText;         
                    if(CCNodes.Count>0) 
                    { 
                        this.LCC.Text=CCNodes[0].InnerText.Replace("<","<").Replace(">",">"); 
 
                    }                 
                    if(importanceNodes.Count>0) 
                    { 
                        if(importanceNodes[0].InnerText=="2") 
                        { 
                            this.LImportance.Text="该邮件重要性为高!"; 
                        } 
                        else if((importanceNodes[0].InnerText=="0")) 
                        {     
                            this.LImportance.Text="该邮件重要性为低!"; 
                        } 
                    } 
                    if(sensitivityNodes.Count>0) 
                    { 
                        if(sensitivityNodes[0].InnerText=="Private") 
                        { 
                            this.Lsensitivity.Text="私人邮件"; 
                        } 
                        else if(sensitivityNodes[0].InnerText=="Personal") 
                        { 
                            this.Lsensitivity.Text="个人邮件"; 
                        } 
                        else if(sensitivityNodes[0].InnerText=="Company-Confidential") 
                        { 
                            this.Lsensitivity.Text="机密邮件"; 
                        }         
                    }                                 
                    this.idBody.InnerHtml=htmldescription[0].InnerText; 
                } 
                if(hasattachmentNodes[0].InnerText=="1") 
                { 
                    this.GetAttachment(displayname); 
                } 
                // Clean up. 
                ResponseStream.Close(); 
                Response.Close(); 
            } 
            catch(Exception ex) 
            { 
                // Catch any exceptions. Any error codes from the SEARCH 
                // method request on the server will be caught here, also.         
                Context.Response.Write(ex.Message); 
            } 
        } 
 
        private void GetAttachment(string displayname) 
        { 
            // Variables. 
            System.Net.HttpWebRequest Request; 
            System.Net.WebResponse Response; 
            System.Net.CredentialCache MyCredentialCache; 
            string userID=User.Identity.Name.Trim(); 
            string password=DAL.Data.UserModel.SelectByUserId(userID).Password.Trim(); 
//            string strMessageURI = "http://191.0.0.111/exchange/administrator/收件箱/"+displayname; 
//            string strUserName = "administrator"; 
            string strMessageURI = "http://191.0.0.111/exchange/"+userID+"/收件箱/"+displayname; 
            string strUserName = userID; 
            string strPassword = password; 
            string strDomain = "oa.lgyw"; 
            System.IO.Stream ResponseStream = null; 
            System.Xml.XmlDocument ResponseXmlDoc = null; 
            System.Xml.XmlNode root = null; 
            System.Xml.XmlNamespaceManager nsmgr = null; 
            System.Xml.XmlNodeList PropstatNodes = null; 
            System.Xml.XmlNodeList HrefNodes = null; 
            System.Xml.XmlNode StatusNode = null; 
            System.Xml.XmlNode PropNode = null; 
 
            string[] _attachmentName=null; 
 
            System.Xml.XmlNode NameNode=null; 
            try 
            { 
                // Create a new CredentialCache object and fill it with the network 
                // credentials required to access the server. 
                MyCredentialCache = new System.Net.CredentialCache(); 
                MyCredentialCache.Add( new System.Uri(strMessageURI), 
                    "NTLM", 
                    new System.Net.NetworkCredential(strUserName, strPassword, strDomain) 
                    ); 
 
                // Create the HttpWebRequest object. 
                Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strMessageURI); 
 
                // Add the network credentials to the request. 
                Request.Credentials = MyCredentialCache; 
 
                // Specify the method. 
                Request.Method = "X-MS-ENUMATTS"; 
 
                // Send the X-MS-ENUMATTS method request and get the 
                // response from the server. 
                Response = (HttpWebResponse)Request.GetResponse(); 
 
                // Get the XML response stream. 
                ResponseStream = Response.GetResponseStream(); 
 
                // Create the XmlDocument object from the XML response stream. 
                ResponseXmlDoc = new System.Xml.XmlDocument(); 
 
                // Load the XML response stream. 
                ResponseXmlDoc.Load(ResponseStream); 
 
                // Get the root node. 
                root = ResponseXmlDoc.DocumentElement; 
 
                // Create a new XmlNamespaceManager. 
                nsmgr = new System.Xml.XmlNamespaceManager(ResponseXmlDoc.NameTable); 
 
                // Add the DAV: namespace, which is typically assigned the a: prefix 
                // in the XML response body.  The namespaceses and their associated 
                // prefixes are listed in the attributes of the DAV:multistatus node 
                // of the XML response. 
                nsmgr.AddNamespace("a", "DAV:"); 
 
                // Add the http://schemas.microsoft.com/mapi/proptag/ namespace, which 
                // is typically assigned the d: prefix in the XML response body. 
                nsmgr.AddNamespace("d", "http://schemas.microsoft.com/mapi/proptag/"); 
 
                // Use an XPath query to build a list of the DAV:propstat XML nodes, 
                // corresponding to the returned status and properties of 
                // the file attachment(s). 
                PropstatNodes = root.SelectNodes("//a:propstat", nsmgr); 
 
                // Use an XPath query to build a list of the DAV:href nodes, 
                // corresponding to the URIs of the attachement(s) on the message. 
                // For each DAV:href node in the XML response, there is an 
                // associated DAV:propstat node. 
                HrefNodes = root.SelectNodes("//a:href", nsmgr); 
                 
                // Attachments found? 
                if(HrefNodes.Count > 0) 
                { 
                    _attachmentName=new string[HrefNodes.Count]; 
                    // Display the number of attachments on the message. 
                    // Iterate through the attachment properties. 
                    for(int i=0;i<HrefNodes.Count;i++) 
                    { 
                        // Use an XPath query to get the DAV:status node from the DAV:propstat node. 
                        StatusNode = PropstatNodes.SelectSingleNode("a:status", nsmgr); 
 
                        // Check the status of the attachment properties. 
                        if(StatusNode.InnerText != "HTTP/1.1 200 OK") 
                        { 
                            return; 
                        } 
                        else 
                        { 
                             
                            // Get the CdoPR_ATTACH_FILENAME_W MAPI property tag, 
                            // corresponding to the attachment file name.  The 
                            // http://schemas.microsoft.com/mapi/proptag/ namespace is typically 
                            // assigned the d: prefix in the XML response body. 
                            NameNode = PropstatNodes.SelectSingleNode("a:prop/d:x3704001f", nsmgr); 
                            // Get the CdoPR_ATTACH_SIZE MAPI property tag, 
                            // corresponding to the attachment file size. 
                            PropNode = PropstatNodes.SelectSingleNode("a:prop/d:x0e200003", nsmgr); 
                            string size; 
                            if(Convert.ToInt32(PropNode.InnerText)>1024*1224) 
                            { 
                                size=(Convert.ToInt32(PropNode.InnerText)/(1024*1024)).ToString()+"M"; 
                            } 
                            else if(Convert.ToInt32(PropNode.InnerText)>1024) 
                            { 
                                size=(Convert.ToInt32(PropNode.InnerText)/1024).ToString()+"KB"; 
                            } 
                            else 
                            { 
                                size=PropNode.InnerText+"B"; 
                            } 
                            int index=HrefNodes.InnerText.LastIndexOf('/')+1; 
                            string attachmentName=HrefNodes.InnerText.Substring(index);                             
                            int    mLastIndex=attachmentName.LastIndexOf('.'); 
                            string mMainName=attachmentName.Substring(0,mLastIndex); 
                            mMainName=Server.UrlDecode(mMainName); 
                            int mExtLength=attachmentName.Length - mLastIndex; 
                            string mExtName= attachmentName.Substring(mLastIndex,mExtLength);                 
                            this.LAttachment.Text+="<a href=\"MailAttachment/"+displayname+"/"+mMainName+"."+mExtName+"\" target=\"_blank\">"+mMainName+"."+mExtName+"("+size+")</a>    "; 
                            _attachmentName=mMainName+"."+mExtName; 
                        } 
                    } 
                     
                }                 
 
                // Clean up. 
                ResponseStream.Close(); 
                Response.Close(); 
     
            } 
            catch(Exception ex) 
            { 
                // Catch any exceptions. Any error codes from the X-MS-ENUMATTS 
                // method request on the server will be caught here, also. 
                 
            } 
            this.GetAttachmentFile(displayname,HrefNodes.Count,_attachmentName); 
        } |   
 
 
 
 |