在 C# 中使用 WebDav 发送/转发具有重复主题行的电子邮件
我有一些代码使用 WEBDAV“搜索”方法从 Exchange 邮箱“收件箱”文件夹中检索电子邮件 - 我的代码采用 HTTPWebRquests WEB 响应的innerXML。
在这些 namsspaces 上使用“selectingSingleNode”:
“urn:schemas:httpmail”& urn:schemas:mailheader
允许我提取元素:
f:textdescription d:来自d:主题 f:datareceived...等等,然后
我在列表中创建这些详细信息的集合,并使用“主题”和 URI,使用“PUT”方法在“草稿”文件夹中重新创建这些消息,然后再使用“移动” ' 发送邮件(使用 '/##DavMailSubmissionURI##/"' 语句将它们放入已发送的项目中。
我遇到的问题是我正在处理的电子邮件的性质往往具有相同的主题行,因此它对哪些电子邮件已发送/或未发送感到困惑。
有谁知道解决此问题的方法吗?我不知道为什么“PUT”依赖于邮件资源的 URI 的主题行,而不是说唯一的 HREF 标记。任何想法:
代码如下:
public class EmailReaderWebDav
{
public enum enmHTTPType
{
HTTP,
HTTPS,
}
private String strServer { get; set; } //"mail1" ------ Exchange server name
public String strPassword { get; set; } //"password" ------ Account Domain Password
public String strDomain { get; set; } //"mydocmian" ------ Domain
public String strMailBox { get; set; } //"mymailbox" ------ UserName
public String mailFolder { get; set; } //"inbox" ------ Mail Folder
private String httpProtocol { get; set; } //http:// ? or https://
private String mailboxURI { get; set; } //httpprotocol// + strserver + "/exhange/" + strmailbox
public List<MailStruct > ListOfEmailDetails { get; private set; }
private String strQuerySearch { get; set; }
public EmailReaderWebDav(String serverName, String domain, String mailBox, String password, String mailmailFolder,enmHTTPType HTTPType)
{
strServer = serverName;
strDomain = domain;
strMailBox = mailBox;
strPassword = password;
mailFolder = mailmailFolder;
httpProtocol = (HTTPType == enmHTTPType.HTTPS) ? "https://" : "http://";
mailboxURI = httpProtocol + strServer + "/exchange/" + strMailBox + "/inbox/";
}
public void forwardEmails(List<MailStruct> emailsToSend)
{
emailsToSend.ForEach(x => SendEmail(x,enmHTTPType.HTTP ));
}
public void MakeListofEmailsToForward()
{
String tmpQuery =
"<?xml version=\"1.0\"?>"
+ "<D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>"
+ " SELECT "
+ "\"urn:schemas:mailheader:to\","
+ "\"urn:schemas:mailheader:from\","
+ "\"urn:schemas:mailheader:subject\","
+ "\"urn:schemas:httpmail:datereceived\","
+ "\"urn:schemas:httpmail:textdescription\""
+ " FROM \"" + mailboxURI + "\""
+ " WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"
+ "</D:sql>"
+ "</D:searchrequest>";
// Search Request to get emails from target folder.
HttpWebRequest SearchRequest = MakeWebRequest("SEARCH", "text/xml", mailboxURI);
Byte[] bytes = Encoding.UTF8.GetBytes((String)tmpQuery);
SearchRequest.ContentLength = bytes.Length;
Stream SearchRequestStream = SearchRequest.GetRequestStream();
SearchRequestStream.Write(bytes, 0, bytes.Length);
SearchRequestStream.Close();
// get the webresponse from the searchrequest.
WebResponse SearchResponse = MakeWebResponse(SearchRequest);
String EmailsInXML = extractXMLFromWebResponse(SearchResponse);
ListOfEmailDetails = extractMailPropertiesFromXMLString(EmailsInXML);
}
public void SendEmail(MailStruct mailToForward, enmHTTPType HTTPType)
{
String submissionUri = httpProtocol + strServer + "/" + "exchange" + "/" + strMailBox + "/##DavMailSubmissionURI##/";
String draftsUri = httpProtocol + strServer + "/" +"exchange" + "/" + strMailBox + "/Drafts/" + mailToForward.Subject + ".eml";
String message = "To: " + mailToForward.To + "\n"
+ "Subject: " + mailToForward.Subject + "\n"
+ "Date: " + mailToForward.Received
+ "X-Mailer: mailer" + "\n"
+ "MIME-Version: 1.0" + "\n"
+ "Content-Type: text/plain;" + "\n"
+ "Charset = \"iso-8859-1\"" + "\n"
+ "Content-Transfer-Encoding: 7bit" + "\n"
+ "\n" + mailToForward.MailBody;
// Request to put an email the drafts folder.
HttpWebRequest putRequest = MakeWebRequest("PUT", "message/rfc822",draftsUri );
Byte[] bytes = Encoding.UTF8.GetBytes((String)message);
putRequest.Headers.Add("Translate", "f");
putRequest.Timeout = 300000;
putRequest.ContentLength = bytes.Length;
Stream putRequestStream = putRequest.GetRequestStream();
putRequestStream.Write(bytes, 0, bytes.Length);
putRequestStream.Close();
// Put the message in the Drafts folder of the sender's mailbox.
HttpWebResponse putResponse = MakeWebResponse(putRequest);
putResponse.Close();
// Request to move the email from the drafts to the mail submission Uri.
HttpWebRequest moveRequest = MakeWebRequest("MOVE", "text/xml", draftsUri);
moveRequest.Headers.Add("Destination", submissionUri);
// Put the message in the mail submission folder.
HttpWebResponse moveResponse = MakeWebResponse(moveRequest);
moveResponse.Close();
}
private CredentialCache getCredentials(String URI)
{
CredentialCache tmpCreds = new CredentialCache();
tmpCreds.Add(new Uri(URI), "NTLM", new NetworkCredential(strMailBox, strPassword,strDomain ));
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
return tmpCreds;
}
private HttpWebRequest MakeWebRequest(String method,String contentType,String URI)
{
HttpWebRequest tmpWebRequest;
tmpWebRequest = (HttpWebRequest)HttpWebRequest.Create(URI);
tmpWebRequest.Credentials = getCredentials (URI);
tmpWebRequest.Method = method;
tmpWebRequest.ContentType = contentType ;
return tmpWebRequest ;
}
private HttpWebResponse MakeWebResponse(HttpWebRequest webRequest)
{
HttpWebResponse tmpWebresponse = (HttpWebResponse)webRequest.GetResponse();
return tmpWebresponse;
}
WebResponse getMailsFromWebRequest(String strRootURI, String strQuerySearch)
{
HttpWebRequest SEARCHRequest;
WebResponse SEARCHResponse;
CredentialCache MyCredentialCache;
Byte[] bytes = null;
Stream SEARCHRequestStream = null;
try
{
MyCredentialCache = new CredentialCache();
MyCredentialCache.Add(new Uri(strRootURI ), "NTLM", new NetworkCredential(strMailBox.ToLower(), strPassword, strDomain));
SEARCHRequest = (HttpWebRequest)HttpWebRequest.Create(strRootURI );
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
SEARCHRequest.Credentials = MyCredentialCache;
SEARCHRequest.Method = "SEARCH";
SEARCHRequest.ContentType = "text/xml";
bytes = Encoding.UTF8.GetBytes((string)strQuerySearch);
SEARCHRequest.ContentLength = bytes.Length;
SEARCHRequestStream = SEARCHRequest.GetRequestStream();
SEARCHRequestStream.Write(bytes, 0, bytes.Length);
SEARCHResponse =(HttpWebResponse ) SEARCHRequest.GetResponse();
SEARCHRequestStream.Close();
SEARCHRequest.Timeout = 300000;
System.Text.Encoding enc = System.Text.Encoding.Default;
if (SEARCHResponse == null)
{
Console.WriteLine("Response returned NULL!");
}
else
{
Console.WriteLine(SEARCHResponse.ContentLength);
}
return SEARCHResponse;
}
catch (Exception ex)
{
Console.WriteLine("Problem: {0}", ex.Message);
return null;
}
}
private String extractXMLFromWebResponse(WebResponse SearchResponse)
{
String tmpStream;
using(StreamReader strmReader = new StreamReader(SearchResponse.GetResponseStream(), System.Text.Encoding.ASCII))
{
tmpStream = strmReader.ReadToEnd();
strmReader.Close();
}
return tmpStream;
}
private List<MailStruct > extractMailPropertiesFromXMLString(String strXmlStream)
{
List<MailStruct> tmpListOfMailProperties = new List<MailStruct>();
XmlDocument doc = new XmlDocument();
doc.InnerXml = strXmlStream ;
XmlNamespaceManager xmlNameSpaces = new XmlNamespaceManager(doc.NameTable);
xmlNameSpaces.AddNamespace("a", "DAV:");
xmlNameSpaces.AddNamespace("f", "urn:schemas:httpmail:");
xmlNameSpaces.AddNamespace("d", "urn:schemas:mailheader:");
XmlNodeList mailNodes = doc.SelectNodes("//a:propstat[a:status='HTTP/1.1 200 OK']/a:prop", xmlNameSpaces);
foreach (XmlElement node in mailNodes)
{
tmpListOfMailProperties.Add(new MailStruct()
{
MailBody = node.SelectSingleNode("//f:textdescription",xmlNameSpaces ).InnerText ,
from = node.SelectSingleNode ("//d:from",xmlNameSpaces ).InnerText ,
To = "[email protected]",
Subject = node.SelectSingleNode("//d:subject",xmlNameSpaces ).InnerText.ToString () ,
Received = node.SelectSingleNode ("//f:datereceived",xmlNameSpaces ).InnerText.ToString ()
}
);
}
return tmpListOfMailProperties;
}
public struct MailStruct
{
public String To { get; set; }
public String from { get; set; }
public String Subject { get; set; }
public String Received { get; set; }
public String MailBody { get; set; }
}
}
}
I have some code that uses the WEBDAV 'SEARCH' method to retrieve emails from an an Exchange Mailboxs 'Inbox' folder - my code takes the the innerXML of the HTTPWebRquests WEBresponse.
Using 'selectingSingleNode' on these namsspaces:
'urn:schemas:httpmail' & urn:schemas:mailheader
Alows me to extract the elements:
f:textdescription
d:fromd:subject
f:datareceived...and so on
I then create a collection of these details in a list and using the 'Subject' along with the URI use the 'PUT' method to recreate these messages in the 'draft's folder before using the 'MOVE' to send the mails (puts them in the sent items using '/##DavMailSubmissionURI##/"' statement.
The problem i have is the nature of the emails i am dealing with tend to come in with the same subject line so it gets confused with which emails have been sent/or not.
Does anyone know of a way around this, I dont know why the 'PUT' relies on the Subject line for the URI to the mail resource rather than say the HREF tag which is unique. Any ideas:
Code is below:
public class EmailReaderWebDav
{
public enum enmHTTPType
{
HTTP,
HTTPS,
}
private String strServer { get; set; } //"mail1" ------ Exchange server name
public String strPassword { get; set; } //"password" ------ Account Domain Password
public String strDomain { get; set; } //"mydocmian" ------ Domain
public String strMailBox { get; set; } //"mymailbox" ------ UserName
public String mailFolder { get; set; } //"inbox" ------ Mail Folder
private String httpProtocol { get; set; } //http:// ? or https://
private String mailboxURI { get; set; } //httpprotocol// + strserver + "/exhange/" + strmailbox
public List<MailStruct > ListOfEmailDetails { get; private set; }
private String strQuerySearch { get; set; }
public EmailReaderWebDav(String serverName, String domain, String mailBox, String password, String mailmailFolder,enmHTTPType HTTPType)
{
strServer = serverName;
strDomain = domain;
strMailBox = mailBox;
strPassword = password;
mailFolder = mailmailFolder;
httpProtocol = (HTTPType == enmHTTPType.HTTPS) ? "https://" : "http://";
mailboxURI = httpProtocol + strServer + "/exchange/" + strMailBox + "/inbox/";
}
public void forwardEmails(List<MailStruct> emailsToSend)
{
emailsToSend.ForEach(x => SendEmail(x,enmHTTPType.HTTP ));
}
public void MakeListofEmailsToForward()
{
String tmpQuery =
"<?xml version=\"1.0\"?>"
+ "<D:searchrequest xmlns:D = \"DAV:\" >"
+ "<D:sql>"
+ " SELECT "
+ "\"urn:schemas:mailheader:to\","
+ "\"urn:schemas:mailheader:from\","
+ "\"urn:schemas:mailheader:subject\","
+ "\"urn:schemas:httpmail:datereceived\","
+ "\"urn:schemas:httpmail:textdescription\""
+ " FROM \"" + mailboxURI + "\""
+ " WHERE \"DAV:ishidden\" = false AND \"DAV:isfolder\" = false"
+ "</D:sql>"
+ "</D:searchrequest>";
// Search Request to get emails from target folder.
HttpWebRequest SearchRequest = MakeWebRequest("SEARCH", "text/xml", mailboxURI);
Byte[] bytes = Encoding.UTF8.GetBytes((String)tmpQuery);
SearchRequest.ContentLength = bytes.Length;
Stream SearchRequestStream = SearchRequest.GetRequestStream();
SearchRequestStream.Write(bytes, 0, bytes.Length);
SearchRequestStream.Close();
// get the webresponse from the searchrequest.
WebResponse SearchResponse = MakeWebResponse(SearchRequest);
String EmailsInXML = extractXMLFromWebResponse(SearchResponse);
ListOfEmailDetails = extractMailPropertiesFromXMLString(EmailsInXML);
}
public void SendEmail(MailStruct mailToForward, enmHTTPType HTTPType)
{
String submissionUri = httpProtocol + strServer + "/" + "exchange" + "/" + strMailBox + "/##DavMailSubmissionURI##/";
String draftsUri = httpProtocol + strServer + "/" +"exchange" + "/" + strMailBox + "/Drafts/" + mailToForward.Subject + ".eml";
String message = "To: " + mailToForward.To + "\n"
+ "Subject: " + mailToForward.Subject + "\n"
+ "Date: " + mailToForward.Received
+ "X-Mailer: mailer" + "\n"
+ "MIME-Version: 1.0" + "\n"
+ "Content-Type: text/plain;" + "\n"
+ "Charset = \"iso-8859-1\"" + "\n"
+ "Content-Transfer-Encoding: 7bit" + "\n"
+ "\n" + mailToForward.MailBody;
// Request to put an email the drafts folder.
HttpWebRequest putRequest = MakeWebRequest("PUT", "message/rfc822",draftsUri );
Byte[] bytes = Encoding.UTF8.GetBytes((String)message);
putRequest.Headers.Add("Translate", "f");
putRequest.Timeout = 300000;
putRequest.ContentLength = bytes.Length;
Stream putRequestStream = putRequest.GetRequestStream();
putRequestStream.Write(bytes, 0, bytes.Length);
putRequestStream.Close();
// Put the message in the Drafts folder of the sender's mailbox.
HttpWebResponse putResponse = MakeWebResponse(putRequest);
putResponse.Close();
// Request to move the email from the drafts to the mail submission Uri.
HttpWebRequest moveRequest = MakeWebRequest("MOVE", "text/xml", draftsUri);
moveRequest.Headers.Add("Destination", submissionUri);
// Put the message in the mail submission folder.
HttpWebResponse moveResponse = MakeWebResponse(moveRequest);
moveResponse.Close();
}
private CredentialCache getCredentials(String URI)
{
CredentialCache tmpCreds = new CredentialCache();
tmpCreds.Add(new Uri(URI), "NTLM", new NetworkCredential(strMailBox, strPassword,strDomain ));
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
return tmpCreds;
}
private HttpWebRequest MakeWebRequest(String method,String contentType,String URI)
{
HttpWebRequest tmpWebRequest;
tmpWebRequest = (HttpWebRequest)HttpWebRequest.Create(URI);
tmpWebRequest.Credentials = getCredentials (URI);
tmpWebRequest.Method = method;
tmpWebRequest.ContentType = contentType ;
return tmpWebRequest ;
}
private HttpWebResponse MakeWebResponse(HttpWebRequest webRequest)
{
HttpWebResponse tmpWebresponse = (HttpWebResponse)webRequest.GetResponse();
return tmpWebresponse;
}
WebResponse getMailsFromWebRequest(String strRootURI, String strQuerySearch)
{
HttpWebRequest SEARCHRequest;
WebResponse SEARCHResponse;
CredentialCache MyCredentialCache;
Byte[] bytes = null;
Stream SEARCHRequestStream = null;
try
{
MyCredentialCache = new CredentialCache();
MyCredentialCache.Add(new Uri(strRootURI ), "NTLM", new NetworkCredential(strMailBox.ToLower(), strPassword, strDomain));
SEARCHRequest = (HttpWebRequest)HttpWebRequest.Create(strRootURI );
ServicePointManager.ServerCertificateValidationCallback = delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate pCertificate, System.Security.Cryptography.X509Certificates.X509Chain pChain, System.Net.Security.SslPolicyErrors pSSLPolicyErrors)
{
return true;
};
SEARCHRequest.Credentials = MyCredentialCache;
SEARCHRequest.Method = "SEARCH";
SEARCHRequest.ContentType = "text/xml";
bytes = Encoding.UTF8.GetBytes((string)strQuerySearch);
SEARCHRequest.ContentLength = bytes.Length;
SEARCHRequestStream = SEARCHRequest.GetRequestStream();
SEARCHRequestStream.Write(bytes, 0, bytes.Length);
SEARCHResponse =(HttpWebResponse ) SEARCHRequest.GetResponse();
SEARCHRequestStream.Close();
SEARCHRequest.Timeout = 300000;
System.Text.Encoding enc = System.Text.Encoding.Default;
if (SEARCHResponse == null)
{
Console.WriteLine("Response returned NULL!");
}
else
{
Console.WriteLine(SEARCHResponse.ContentLength);
}
return SEARCHResponse;
}
catch (Exception ex)
{
Console.WriteLine("Problem: {0}", ex.Message);
return null;
}
}
private String extractXMLFromWebResponse(WebResponse SearchResponse)
{
String tmpStream;
using(StreamReader strmReader = new StreamReader(SearchResponse.GetResponseStream(), System.Text.Encoding.ASCII))
{
tmpStream = strmReader.ReadToEnd();
strmReader.Close();
}
return tmpStream;
}
private List<MailStruct > extractMailPropertiesFromXMLString(String strXmlStream)
{
List<MailStruct> tmpListOfMailProperties = new List<MailStruct>();
XmlDocument doc = new XmlDocument();
doc.InnerXml = strXmlStream ;
XmlNamespaceManager xmlNameSpaces = new XmlNamespaceManager(doc.NameTable);
xmlNameSpaces.AddNamespace("a", "DAV:");
xmlNameSpaces.AddNamespace("f", "urn:schemas:httpmail:");
xmlNameSpaces.AddNamespace("d", "urn:schemas:mailheader:");
XmlNodeList mailNodes = doc.SelectNodes("//a:propstat[a:status='HTTP/1.1 200 OK']/a:prop", xmlNameSpaces);
foreach (XmlElement node in mailNodes)
{
tmpListOfMailProperties.Add(new MailStruct()
{
MailBody = node.SelectSingleNode("//f:textdescription",xmlNameSpaces ).InnerText ,
from = node.SelectSingleNode ("//d:from",xmlNameSpaces ).InnerText ,
To = "[email protected]",
Subject = node.SelectSingleNode("//d:subject",xmlNameSpaces ).InnerText.ToString () ,
Received = node.SelectSingleNode ("//f:datereceived",xmlNameSpaces ).InnerText.ToString ()
}
);
}
return tmpListOfMailProperties;
}
public struct MailStruct
{
public String To { get; set; }
public String from { get; set; }
public String Subject { get; set; }
public String Received { get; set; }
public String MailBody { get; set; }
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
仅仅使用主题来识别电子邮件确实不是一个好方法。如果我没记错的话,没有用于交换/webdav 的自动/明显的电子邮件 ID 吗?
如果您解析主题来选择消息,我还会选择电子邮件信封的更多信息 - 比如它的大小、长度来创建我自己的 ID。最好的步骤应该是从整个邮件正文中创建某种哈希(检查密码学),或者即电子邮件正文中第一个 xx 单词的第一个字符(尽管处理较繁重)。每次您在同一个电子邮件信封上调用它时,最终都会得到相同的哈希值。直到电子邮件内容保持不变。
Using just the subject to identify email is, indeed, not a good way. If I remember it's correct, there are no automatic / obvious email id for exchange / webdav?
If you parse the subject to pick message, I would also pick more information of the email envelope - Like it size, length to create my own id. The best step should be that you create some sort of hash (check Cryptography) out of the whole message body OR i.e. first character of first xx word in the email body (heavier processing though). That will end up in same hash value everytime you call it on same email envelope. Of until the email content is leaved unchanged.
看起来您正在使用 Exchange 2003。请注意,Exchange 版本 2010 不再支持 WebDAV...而在 2007 及更高版本中,您可以使用 WSDL 来执行您需要的所有操作。您只需要一个 Exchange 2007 CAS 即可完成此操作。
我提到的是一种更好的长期方法,并且比解析不受支持的 WEBDAV XML 更少麻烦。
要回答您的问题,有一个每条消息都是唯一的属性。使用 MFCMapi(在 codeplex 上)来查找它。该属性将被命名为“MessageURL”或类似名称。在 URL 中使用该属性进行 webdav 调用。
Looks like you're working with Exchange 2003. Be aware that WebDAV is no longer supported in Exchange Version 2010... and with 2007 and newer you can use a WSDL to do everything you need. All you need is an Exchange 2007 CAS to do this.
What I mentioned is a better longer term approach and has less headaches than parsing unsupported WEBDAV XML
To answer your question, there is a property that is unique per message. Use MFCMapi (on codeplex) to look for it. The property will be named "MessageURL" or something like that. Use that property in the URL for your webdav calls.