在SharePoint的项目中,经常会把SharePoint 和Exchange整合到一起,所以我们经常会遇到读取OWA中未读邮件的问题,当然解决的方法 也是多种多样的。有以下几种:
1. WebDAV的方式
示例代码:
private int GetUnReadMailCount()
{
string url = "http://10.10.10.254/exchange/"; //指定Exchange服务器地址
System.NET.HttpWebRequest Request;
System.NET.WebResponse Response;
System.NET.CredentialCache MyCredentialCache;
string strUserName = UserName; //指定登录的用户名
string strRootURI = url + strUserName; //得到要访问邮箱的WebDAV地址
string strPassword = PassWord; //指定该用户的密码
string strDomain = "unique.com"; //指定域名
string strQuery = "";
byte[] bytes = null;
System.IO.Stream RequestStream = null;
System.IO.Stream ResponseStream = null;
XMLDocument ResponseXmlDoc = null;
XMLNodeList HrefNodes = null;
XMLNodeList SizeNodes = null;
int count = 0;
try
{
// 用SQL查询WebDAV返回结果中的unreadcount节点.
strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>SELECT \"DAV:displayname\",\"urn:schemas:httpmail:unreadcount\" FROM \"" + strRootURI + "\""
+ "</D:sql></D:searchrequest>";
// 创建新的CredentialCache对象,构建身份凭据
MyCredentialCache = new System.NET.CredentialCache();
MyCredentialCache.Add(new System.Uri(strRootURI), "NTLM",
new System.NET.NetworkCredential(strUserName, strPassword, strDomain));
// Create the HttpWebRequest object.
Request = (System.NET.HttpWebRequest)HttpWebRequest.Create(strRootURI);
// 指定HttpWebRequest的身份凭据,此处为关键所在。如果使用之前
// 创建的MyCredentialCache,则这个身份凭据是可以从Web服务器传递
// 到Exchange服务器的,但是这样带来的问题也很明显,就是不能够自
// 动获取当前登录到域的用户的身份。即便已经成功登录到域,那也只
// 能通过form再次输入用户名密码。因此,我在这里用的是
// Request.Credentials = CredentialCache.DefaultCredentials,
// 这样便可以获得当前用户的凭据,但是这样带来的问题便是上面提到的
// 身份凭据无法传递的问题,解决方法请关注下篇文章。
Request.Credentials = MyCredentialCache;
// 指定WebDAV的SEARCH方法
Request.Method = "SEARCH";
// Encode the body using UTF-8.
bytes = Encoding.UTF8.GetBytes((string)strQuery);
// 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 SQL query 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 SEARCH method request and get the
// response from the server.
Response = (HttpWebResponse)Request.GetResponse();
// Get the XML response stream.
ResponseStream = Response.GetResponseStream();
// 创建XMLDocument对象,并获取收件箱的unreadcount节点的值
ResponseXMLDoc = new XmlDocument();
ResponseXMLDoc.Load(ResponseStream);
HrefNodes = ResponseXMLDoc.GetElementsByTagName("a:displayname");
SizeNodes = ResponseXMLDoc.GetElementsByTagName("d:unreadcount");
for (int i = 0; i < HrefNodes.Count; i++)
{
if (HrefNodes[i].InnerText == "收件箱")
count = int.Parse(SizeNodes[i].InnerText);
}
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.
return -1;
}
return count;
}
缺点主要在用户的凭证上面。
a. 通过用户的用户名和密码进行身份的认证。可以通过SharePoint的SSO存储用户的凭证信息
b. 加域的机器通过默认的身份凭证信息进行身份认证。这里面会有一个认证的设置。因为SharePoint中默认的认证方式是NTLM,认证的时候,需要使用用户名和密码,而Kerberos认证是通过票据进行认证的。所以我们要把相应的认证方式进行设置。详细的操作请参考http://security.ctocio.com.cn/tips/121/8274121.sHTML。我按这种方式没有成功,如果有人弄成功了,可以告诉我一下,怎么弄的。
2. 通过Exchange Web Services方式
通过Exchange Web Services 访问的方式也有2中得到未读邮件的方式:
a. 通过用户的用户名和密码进行认证,查询自己的未读邮件
示例代码:
Code
b. 通过身份模拟的方式进行,这个好像只有Exchange 2007 中才有
示例代码:
protected int GetUnreadMailCount()
{
try
{
string domianUserName = System.Configuration.ConfigurationSettings.AppSettings["DomianAdmin"];
string domianPassword = System.Configuration.ConfigurationSettings.AppSettings["DomainPwd"];
string domainName = System.Configuration.ConfigurationSettings.AppSettings["DomainName"];
System.NET.NetworkCredential nc = new System.Net.NetworkCredential(domianUserName, domianPassword, domainName);
System.NET.ServicePointManager.ServerCertificateValidationCallback =
delegate(Object obj, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.NET.Security.SslPolicyErrors errors)
{
return true;
};
string exchUrl = System.Configuration.ConfigurationSettings.AppSettings["SMTPServer"];
string emEmailAddress = string.Empty;
string userName = SPContext.Current.Web.CurrentUser.LoginName;
emEmailAddress = userName.Substring(userName.IndexOf("\\") + 1) + "@" + domainName;
// Response.Write("LoginName :" + userName.Substring(userName.IndexOf("\\") + 1));
ExchangeServiceBinding esb = new ExchangeServiceBinding();
esb.Url = string.Format("https://{0}/EWS/Exchange.asmx", exchUrl);
esb.Credentials = nc;
ExchangeImpersonationType exExchangeImpersonation = new ExchangeImpersonationType();
ConnectingSIDType csConnectingSid = new ConnectingSIDType();
csConnectingSid.PrimarySmtpAddress = emEmailAddress;
exExchangeImpersonation.ConnectingSID = csConnectingSid;
esb.ExchangeImpersonation = exExchangeImpersonation;
FindItemType findItemRequest = new FindItemType();
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
ItemResponseShapeType itemProperties = new ItemResponseShapeType();
itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
findItemRequest.ItemShape = itemProperties;
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.inbox;
findItemRequest.ParentFolderIds = folderIDArray;
RestrictionType restriction = new RestrictionType();
IsEqualToType isEqualTo = new IsEqualToType();
PathToUnindexedFieldType pathToFieldType = new PathToUnindexedFieldType();
pathToFieldType.FieldURI = UnindexedFieldURIType.messageIsRead;
FieldURIOrConstantType constantType = new FieldURIOrConstantType();
ConstantValueType constantValueType = new ConstantValueType();
constantValueType.Value = "0";
constantType.Item = constantValueType;
isEqualTo.Item = pathToFieldType;
isEqualTo.FieldURIOrConstant = constantType;
restriction.Item = isEqualTo;
findItemRequest.Restriction = restriction;
FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);
FindItemResponseMessageType folder = (FindItemResponseMessageType)findItemResponse.ResponseMessages.Items[0];
ArrayOfRealItemsType folderContents = new ArrayOfRealItemsType();
folderContents = (ArrayOfRealItemsType)folder.RootFolder.Item;
ItemType[] items = folderContents.Items;
return items == null ? 0 : items.Length;
}
catch (Exception ex)
{
//Response.Write(ex);
return 0;
}
return 0;
}
优点:
可以不用域环境就能访问用户的未读邮件
缺点:
直接使用代码是没有用的,会提示相应的错误信息:
The server to which the application is connected cannot impersonate the requested user due to insufficient permission.
必须在Exchange上的控制台上面使用以下的命令,才能正常的使用:
foreach ($exchangeServer in Get-ExchangeServer)
{
if ($exchangeServer.ServerRole -match 'ClientAccess')
{
Add-ADPermission -Identity $exchangeServer.DistinguishedName -User 'domain"user' -ExtendedRights ms-Exch-EPI-Impersonation
}
}
1. WebDAV的方式
示例代码:
private int GetUnReadMailCount()
{
string url = "http://10.10.10.254/exchange/"; //指定Exchange服务器地址
System.NET.HttpWebRequest Request;
System.NET.WebResponse Response;
System.NET.CredentialCache MyCredentialCache;
string strUserName = UserName; //指定登录的用户名
string strRootURI = url + strUserName; //得到要访问邮箱的WebDAV地址
string strPassword = PassWord; //指定该用户的密码
string strDomain = "unique.com"; //指定域名
string strQuery = "";
byte[] bytes = null;
System.IO.Stream RequestStream = null;
System.IO.Stream ResponseStream = null;
XMLDocument ResponseXmlDoc = null;
XMLNodeList HrefNodes = null;
XMLNodeList SizeNodes = null;
int count = 0;
try
{
// 用SQL查询WebDAV返回结果中的unreadcount节点.
strQuery = "<?xml version=\"1.0\"?><D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>SELECT \"DAV:displayname\",\"urn:schemas:httpmail:unreadcount\" FROM \"" + strRootURI + "\""
+ "</D:sql></D:searchrequest>";
// 创建新的CredentialCache对象,构建身份凭据
MyCredentialCache = new System.NET.CredentialCache();
MyCredentialCache.Add(new System.Uri(strRootURI), "NTLM",
new System.NET.NetworkCredential(strUserName, strPassword, strDomain));
// Create the HttpWebRequest object.
Request = (System.NET.HttpWebRequest)HttpWebRequest.Create(strRootURI);
// 指定HttpWebRequest的身份凭据,此处为关键所在。如果使用之前
// 创建的MyCredentialCache,则这个身份凭据是可以从Web服务器传递
// 到Exchange服务器的,但是这样带来的问题也很明显,就是不能够自
// 动获取当前登录到域的用户的身份。即便已经成功登录到域,那也只
// 能通过form再次输入用户名密码。因此,我在这里用的是
// Request.Credentials = CredentialCache.DefaultCredentials,
// 这样便可以获得当前用户的凭据,但是这样带来的问题便是上面提到的
// 身份凭据无法传递的问题,解决方法请关注下篇文章。
Request.Credentials = MyCredentialCache;
// 指定WebDAV的SEARCH方法
Request.Method = "SEARCH";
// Encode the body using UTF-8.
bytes = Encoding.UTF8.GetBytes((string)strQuery);
// 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 SQL query 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 SEARCH method request and get the
// response from the server.
Response = (HttpWebResponse)Request.GetResponse();
// Get the XML response stream.
ResponseStream = Response.GetResponseStream();
// 创建XMLDocument对象,并获取收件箱的unreadcount节点的值
ResponseXMLDoc = new XmlDocument();
ResponseXMLDoc.Load(ResponseStream);
HrefNodes = ResponseXMLDoc.GetElementsByTagName("a:displayname");
SizeNodes = ResponseXMLDoc.GetElementsByTagName("d:unreadcount");
for (int i = 0; i < HrefNodes.Count; i++)
{
if (HrefNodes[i].InnerText == "收件箱")
count = int.Parse(SizeNodes[i].InnerText);
}
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.
return -1;
}
return count;
}
缺点主要在用户的凭证上面。
a. 通过用户的用户名和密码进行身份的认证。可以通过SharePoint的SSO存储用户的凭证信息
b. 加域的机器通过默认的身份凭证信息进行身份认证。这里面会有一个认证的设置。因为SharePoint中默认的认证方式是NTLM,认证的时候,需要使用用户名和密码,而Kerberos认证是通过票据进行认证的。所以我们要把相应的认证方式进行设置。详细的操作请参考http://security.ctocio.com.cn/tips/121/8274121.sHTML。我按这种方式没有成功,如果有人弄成功了,可以告诉我一下,怎么弄的。
2. 通过Exchange Web Services方式
通过Exchange Web Services 访问的方式也有2中得到未读邮件的方式:
a. 通过用户的用户名和密码进行认证,查询自己的未读邮件
示例代码:
Code
b. 通过身份模拟的方式进行,这个好像只有Exchange 2007 中才有
示例代码:
protected int GetUnreadMailCount()
{
try
{
string domianUserName = System.Configuration.ConfigurationSettings.AppSettings["DomianAdmin"];
string domianPassword = System.Configuration.ConfigurationSettings.AppSettings["DomainPwd"];
string domainName = System.Configuration.ConfigurationSettings.AppSettings["DomainName"];
System.NET.NetworkCredential nc = new System.Net.NetworkCredential(domianUserName, domianPassword, domainName);
System.NET.ServicePointManager.ServerCertificateValidationCallback =
delegate(Object obj, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.NET.Security.SslPolicyErrors errors)
{
return true;
};
string exchUrl = System.Configuration.ConfigurationSettings.AppSettings["SMTPServer"];
string emEmailAddress = string.Empty;
string userName = SPContext.Current.Web.CurrentUser.LoginName;
emEmailAddress = userName.Substring(userName.IndexOf("\\") + 1) + "@" + domainName;
// Response.Write("LoginName :" + userName.Substring(userName.IndexOf("\\") + 1));
ExchangeServiceBinding esb = new ExchangeServiceBinding();
esb.Url = string.Format("https://{0}/EWS/Exchange.asmx", exchUrl);
esb.Credentials = nc;
ExchangeImpersonationType exExchangeImpersonation = new ExchangeImpersonationType();
ConnectingSIDType csConnectingSid = new ConnectingSIDType();
csConnectingSid.PrimarySmtpAddress = emEmailAddress;
exExchangeImpersonation.ConnectingSID = csConnectingSid;
esb.ExchangeImpersonation = exExchangeImpersonation;
FindItemType findItemRequest = new FindItemType();
findItemRequest.Traversal = ItemQueryTraversalType.Shallow;
ItemResponseShapeType itemProperties = new ItemResponseShapeType();
itemProperties.BaseShape = DefaultShapeNamesType.IdOnly;
findItemRequest.ItemShape = itemProperties;
DistinguishedFolderIdType[] folderIDArray = new DistinguishedFolderIdType[1];
folderIDArray[0] = new DistinguishedFolderIdType();
folderIDArray[0].Id = DistinguishedFolderIdNameType.inbox;
findItemRequest.ParentFolderIds = folderIDArray;
RestrictionType restriction = new RestrictionType();
IsEqualToType isEqualTo = new IsEqualToType();
PathToUnindexedFieldType pathToFieldType = new PathToUnindexedFieldType();
pathToFieldType.FieldURI = UnindexedFieldURIType.messageIsRead;
FieldURIOrConstantType constantType = new FieldURIOrConstantType();
ConstantValueType constantValueType = new ConstantValueType();
constantValueType.Value = "0";
constantType.Item = constantValueType;
isEqualTo.Item = pathToFieldType;
isEqualTo.FieldURIOrConstant = constantType;
restriction.Item = isEqualTo;
findItemRequest.Restriction = restriction;
FindItemResponseType findItemResponse = esb.FindItem(findItemRequest);
FindItemResponseMessageType folder = (FindItemResponseMessageType)findItemResponse.ResponseMessages.Items[0];
ArrayOfRealItemsType folderContents = new ArrayOfRealItemsType();
folderContents = (ArrayOfRealItemsType)folder.RootFolder.Item;
ItemType[] items = folderContents.Items;
return items == null ? 0 : items.Length;
}
catch (Exception ex)
{
//Response.Write(ex);
return 0;
}
return 0;
}
优点:
可以不用域环境就能访问用户的未读邮件
缺点:
直接使用代码是没有用的,会提示相应的错误信息:
The server to which the application is connected cannot impersonate the requested user due to insufficient permission.
必须在Exchange上的控制台上面使用以下的命令,才能正常的使用:
foreach ($exchangeServer in Get-ExchangeServer)
{
if ($exchangeServer.ServerRole -match 'ClientAccess')
{
Add-ADPermission -Identity $exchangeServer.DistinguishedName -User 'domain"user' -ExtendedRights ms-Exch-EPI-Impersonation
}
}