Hobby Chef

April, 2008 - Jive into Messaging world - Site Home - MSDN Blogs

Blog - Title

April, 2008

  • Jive into Messaging world

    BUG: ASP.net 2.0 PasswordRecovery Web Control cannot send emails to SSL enabled SMTP Servers

    • 11 Comments

    This is a known issue or you can also call it as product limitation. PasswordRecovery control read most of the settings from web.config file. Internally it uses System.Net.Mail to send out email, which does not support reading EnableSSL setting from web.config. This bring us into a situation where PasswordRecovery control cannot send emails to SSL enabled smtp servers.

    So when a user tries to send a email to SSL enable server using PasswordRecovery control, he get the following error.

    Error: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first. 32sm15616652wfa.13

    Cause
    =============================
    There is no setting in Web.Config for System.Net.Mail (.net 2.0) that maps to EnableSSL property of System.Net.Mail.SmtpClient.

    Resolution
    =============================
    1) In the code behind, We need to consume PasswordRecovery1_SendingMail event of the web control
    2) This event provide us access to Email Message being sent and also give us option to cancel the send operation
    3) We will make a copy of this email message, and create a new instance of System.Net.Mail.SmtpClient
    4) This time we have complete access to its properties and we can turn On/Off the EnableSSL setting
    5) Lets set EnableSSL to true and send the email message to desired SMTP server

    The below code snippet can do the job..

    protected void PasswordRecovery1_SendingMail(object sender, MailMessageEventArgs e)
    {
    System.Net.Mail.SmtpClient smtpSender = new System.Net.Mail.SmtpClient("mail.google.com", 587);
    smtpSender.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
    smtpSender.Credentials = new System.Net.NetworkCredential("username@gmail.com", "password");
    smtpSender.EnableSsl = true;

    smtpSender.Send(e.Message);
    e.Cancel = true;
    }


    Repro Steps
    =============================
    1) Configure a PasswordRecovery control
    2) Provide all the settings in Web.Config, including username/password, server name, email sender and others
    3) Try to send a recovery email when SMTP server requires SSL

    More Information
    =============================
    This problem is related to System.Net.Mail and also documented here...
    http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=281277

    I am working on it and trying to get a fixed for the problem, but as most of the bugs there is no ETA :-)

  • Jive into Messaging world

    HOWTO: WebDAV: EWS: Programmatically recover soft deleted items from dumpster

    • 1 Comments

    As you may already know, EWS has support for Soft-Deleting items but the irony is it cannot access the soft-deleted items. This is a design challenge and product group is aware of this limitation. Hopefully we should see this support natively in EWS sooner or later. If you really need a solution or as we term it as "workaround" to the problem, you can still use WebDAV or MAPI to recover them. MAPI is very powerful but cant work from managed code.

    I had faced little tough time to decode the way it works, ofcourse Glen's blog was very helpful, but unfortunately it did not work as expected and I had to create my own code. 

    Disclaimer: This is just a sample code to serve as proof of concept, I would recommend to use MAPI

    See the below KB for MAPI sample code to do the job

    http://support.microsoft.com/kb/232265

     

    public static void WebDAV_RecoverDeletedFolder(string hostname, string user,string pass,string sourceFolder, string targetFolder)
            {

                Console.WriteLine("Info: Searching for \"Soft Deleted\" items in \"" + sourceFolder + "\", will move them to \"" + targetFolder + "\"");

                sourceFolder = sourceFolder.Replace(" ", "%20").ToLower();
                targetFolder = targetFolder.Replace(" ", "%20").ToLower();
                int itemCount = 0;

                string sourceForlderURL = "http://" + hostname + "/exchange/" + user + "/" + sourceFolder;


                #region Search all messages and generate the XML to copy them to new folder
                HttpWebRequest xmlReq = (HttpWebRequest)System.Net.WebRequest.Create(sourceForlderURL);

                StringBuilder strXml = new StringBuilder();
                StringBuilder strXmlForDeletion = new StringBuilder();

                strXml.Append("<?xml version='1.0'?>");
                strXml.Append("<D:searchrequest xmlns:D='DAV:'>");
                strXml.Append("<D:sql>SELECT ");
                strXml.Append("\"DAV:href\"");
                strXml.Append("FROM SCOPE ('SOFTDELETED TRAVERSAL OF \"" + sourceForlderURL + "\"')");
                strXml.Append("</D:sql></D:searchrequest>");

                xmlReq.Credentials = new System.Net.NetworkCredential(user, pass);
                xmlReq.AllowAutoRedirect = true;
                xmlReq.Method = "SEARCH";
                xmlReq.Headers.Add("Translate", "f");
                xmlReq.ContentType = "text/xml";
                xmlReq.ContentLength = strXml.Length;

                StreamWriter sw = new StreamWriter(xmlReq.GetRequestStream());
                sw.Write(strXml.ToString());
                sw.Flush();
                sw.Close();

                strXml.Remove(0, strXml.Length);

                string strOut = string.Empty;
                HttpWebResponse httpResp = (HttpWebResponse)xmlReq.GetResponse();
                if ((int)httpResp.StatusCode > 200 && (int)httpResp.StatusCode < 300)
                    strOut = new StreamReader(httpResp.GetResponseStream()).ReadToEnd();
                else
                    Console.WriteLine("Error: " + httpResp.StatusDescription + " (" + httpResp.StatusCode + "), while searching for deleted items");

                XmlDocument xDoc = new XmlDocument();
                xDoc.LoadXml(strOut);
                XmlNodeList xNodeList = xDoc.GetElementsByTagName("a:href");

                strXml.Append("<?xml version=\"1.0\" ?>");
                strXml.Append("<D:copy xmlns:D=\"DAV:\">");

                itemCount = xNodeList.Count / 2;
                Console.WriteLine("Info: " + itemCount + " deleted items found to recover");

                if (itemCount <= 0)
                    return;

                for (int nCtr = 0; nCtr < xNodeList.Count - 1; nCtr += 2)
                {
                    strXml.Append("<D:target>");
                    strXml.Append("<D:href>" + xNodeList[nCtr].InnerText + "</D:href>");
                    strXml.Append("<D:dest>" + xNodeList[nCtr + 1].InnerText.ToLower().Replace(sourceFolder, targetFolder) + "</D:dest>");
                    strXml.Append("</D:target>");

                    //We will use this XML later for deletion of these items
                    strXmlForDeletion.Append("<D:href>" + xNodeList[nCtr].InnerText + "</D:href>");

                }
                strXml.Append("</D:copy>");

                #endregion

                #region Start Copying all the messages to target folder

                xmlReq = (HttpWebRequest)System.Net.WebRequest.Create(sourceForlderURL);
                xmlReq.Credentials = new System.Net.NetworkCredential(user, pass);
                xmlReq.AllowAutoRedirect = true;
                xmlReq.Method = "BCOPY";
                xmlReq.Headers.Add("Translate", "f");
                xmlReq.ContentType = "text/xml";
                xmlReq.ContentLength = strXml.Length;

                sw = new StreamWriter(xmlReq.GetRequestStream());
                sw.Write(strXml.ToString());
                sw.Flush();
                sw.Close();


                strOut = string.Empty;
                httpResp = (HttpWebResponse)xmlReq.GetResponse();
                if ((int)httpResp.StatusCode > 200 && (int)httpResp.StatusCode < 300)
                {
                    strOut = new StreamReader(httpResp.GetResponseStream()).ReadToEnd();
                    Console.WriteLine("Success: " + itemCount + " Items copied to target folder");
                }
                else
                    Console.WriteLine("Error: " + httpResp.StatusDescription + " (" + httpResp.StatusCode + "), while copying deleted items to target folder");

                #endregion

                #region Delete all the messages from dumpster, to avoid duplication on next run


                strXml.Remove(0, strXml.Length);


                Console.WriteLine("Info: Deleting " + itemCount + " items from dumpster");

                strXml.Append("<?xml version=\"1.0\" ?>");
                strXml.Append("<D:delete xmlns:D=\"DAV:\">");
                strXml.Append("<D:target>");
                strXml.Append(strXmlForDeletion.ToString());
                strXml.Append("</D:target>");
                strXml.Append("</D:delete>");


                xmlReq = (HttpWebRequest)System.Net.WebRequest.Create(sourceForlderURL);
                xmlReq.Credentials = new System.Net.NetworkCredential(user, pass);
                xmlReq.AllowAutoRedirect = true;
                xmlReq.Method = "BDELETE";
                xmlReq.Headers.Add("Translate", "f");
                xmlReq.ContentType = "text/xml";
                xmlReq.ContentLength = strXml.Length;

                sw = new StreamWriter(xmlReq.GetRequestStream());
                sw.Write(strXml.ToString());
                sw.Flush();
                sw.Close();

                strXml.Remove(0, strXml.Length);

                strOut = string.Empty;
                httpResp = (HttpWebResponse)xmlReq.GetResponse();
                if ((int)httpResp.StatusCode > 200 && (int)httpResp.StatusCode < 300)
                {
                    strOut = new StreamReader(httpResp.GetResponseStream()).ReadToEnd();
                    Console.WriteLine("Success: " + itemCount + " Items deleted from dumpster");
                }
                else
                    Console.WriteLine("Error: " + httpResp.StatusDescription + " (" + httpResp.StatusCode + "), while deleting items from dumpster");


                #endregion
            }

     

Page 1 of 1 (2 items)