2

I made a small program in which I can basically send an email through the yahoo smtp server. My Code:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Net;
using System.Net.Mail;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

                try
                {

                    MailMessage message = new MailMessage();
                    message.From = new MailAddress("myid@yahoo.com");
                    message.To.Add("anotherid@yahoo.com");
                    message.Subject = "afdasdfasfg";
                    message.Body = "Hgfk4564267862738I";
                    message.IsBodyHtml = true;
                    message.Priority = MailPriority.High;
                    SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com");
                    sC.Port = 587;
                    sC.Credentials = new NetworkCredential("myid", "mypassword");
                    //sC.EnableSsl = true;
                    sC.Send(message);
                    MessageBox .Show ("Mail Send Successfully");

                }
                catch (Exception ex)
                {
                    MessageBox .Show (ex + "Mail Sending Fail's") ;

                }
            }

        }
    }

The bizarre thing is that it worked for the first week. I could send messages with no problem. Then just yesterday, the program just starts freezing and doesn't respond( I didn't change the code). Why did this happen? How can I mend my program?

Edit: @Andreas Niedermair Right now I just tried the program and left it for a whole minute then an error showed:ContextSwitchDeadlock was detected Message: The CLR has been unable to transition from COM context 0x21eb78 to COM context 0x21ece8 for 60 seconds. The thread that owns the destination context/apartment is most likely either doing a non pumping wait or processing a very long running operation without pumping Windows messages. This situation generally has a negative performance impact and may even lead to the application becoming non responsive or memory usage accumulating continually over time. To avoid this problem, all single threaded apartment (STA) threads should use pumping wait primitives (such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

Thanks for your help!

2 Answers2

1

does your catch ever get reached?

i assume, that you are not patient enough to reach the default value of the Timeout property (100seconds)... you could decrease the value to get an earlier completion.

as long as you are not working with an async-pattern, your UI-thread gets blocked anyway. an alternative would be to use the SendAsync method (there are sample implementations in the msdn-entries for the specific methods).

Edit:
as the author mentioned a possible fu**ed port: yes, it could be. but you would have to read the specification paper, which tells us:

  • SMTP server: plus.smtp.mail.yahoo.com
  • Use SSL
  • Port: 465
  • Use authentication
  • Account Name/Login Name: Your Yahoo! Mail ID (your email address without the "@yahoo.com", for example, “testing80”)
  • Email Address: Your Yahoo! Mail address (for example, testing80@yahoo.com)
  • Password: Your Yahoo! Mail password
  • [...] try setting the SMTP port number to 587 when sending email via Yahoo!'s SMTP server.

but even if you meet the specifications: you should really go for the async-pattern :)

Edit: the mentioned exception is related to COM ... a bit googeling, and i've found this:

What's probably happening is that you have a COM object in a form, and you're doing work on the UI thread. If your UI gets blocked by the processing for >60 seconds, the COM component can complain.

Edit:

otherwise: did you change anything within the exceptions-dialog of visual studio? then this could be your solution, or this one (with some basic explanation)...

  • @Andreas Niedermair Do you think that there could be a problem with the port? –  Nov 24 '10 at 17:50
  • @Andreas Niedermair Right now I just tried the program and left it for a whole minute then an error showed: –  Nov 24 '10 at 17:55
  • @Omar, try setting the port to 25. This is the standard port used for SMTP. – Nathan Ernst Nov 24 '10 at 17:58
  • @Omar: did you try to meet the specification which i've posted? –  Nov 24 '10 at 18:01
  • @Andreas Niedermair Yes, but still the same problems..... it's really frustrating ( I really don't understand about the async-pattern, could you show me how to use it?) –  Nov 24 '10 at 18:04
  • @Omar: please read my last edit, it might be the solution you are longing for :) ... async-pattern is described with an example here: http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx (you may have to switch the framework-version in the upper right) –  Nov 24 '10 at 18:07
  • @Andreas Niedermair What explains the fact that it worked a few days ago then suddenly stopped working? After all I didn't change the code or anything. Could it be something with my network or something similar? –  Nov 24 '10 at 18:18
  • @Omar: please refer to the last link in my answer: http://dotnetcodehelper.blogspot.com/2009/01/clr-has-been-unable-to-transition-from_2130.html (this matches your symptom: no need to change code, just some settings inside visual studio). more details here: http://stackoverflow.com/questions/578357/visual-studio-contextswitchdeadlock –  Nov 24 '10 at 18:19
0

As per Andreas Niedermair edit the issue is you are blocking the main thread for more than 60 secconds. The best thing to do is put this operation on a background thread.

using System;
using System.ComponentModel;
using System.Net;
using System.Net.Mail;
using System.Windows.Forms;

namespace Sandbox_Form
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            bw = new BackgroundWorker();
            bw.DoWork +=new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted +=new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Error != null)
                MessageBox.Show(e.Error.ToString() + "Mail Sending Fail's") ;
            else
                MessageBox.Show("Mail Send Successfully");
        }

        BackgroundWorker bw;

        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            using(MailMessage message = new MailMessage())
            {
                message.From = new MailAddress("myid@yahoo.com");
                message.To.Add("anotherid@yahoo.com");
                message.Subject = "afdasdfasfg";
                message.Body = "Hgfk4564267862738I";
                message.IsBodyHtml = true;
                message.Priority = MailPriority.High;
                using(SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com"))
                {
                    sC.Port = 587;
                    sC.Credentials = new NetworkCredential("myid", "mypassword");
                    //sC.EnableSsl = true;
                    sC.Send(message);
                }
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            bw.RunWorkerAsync();
        }
    }

}

EDIT:

per Andreas Niedermair suggestion, here is a version using the async method instead.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void button1_Click(object sender, EventArgs e)
    {
        try
        {

            MailMessage message = new MailMessage();
            message.From = new MailAddress("myid@yahoo.com");
            message.To.Add("anotherid@yahoo.com");
            message.Subject = "afdasdfasfg";
            message.Body = "Hgfk4564267862738I";
            message.IsBodyHtml = true;
            message.Priority = MailPriority.High;
            SmtpClient sC = new SmtpClient("smtp.mail.yahoo.com");
            sC.Port = 587;
            sC.Credentials = new NetworkCredential("myid", "mypassword");
            //sC.EnableSsl = true;
            //sC.Send(message);
            sC.SendCompleted += new SendCompletedEventHandler(sC_SendCompleted);
            sC.SendAsync(message, null);

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex + "Mail Sending Fail's");
        }

    }

    void sC_SendCompleted(object sender, AsyncCompletedEventArgs e)
    {
        if(e.Error != null)
            MessageBox.Show(ex + "Mail Sending Fail's");
        else
            MessageBox.Show("Mail Send Successfully");
    }
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • do you really need to create a new backroundworker-thread? why not use the `SendAsync`-method with some callback? –  Nov 24 '10 at 19:30
  • I was not familiar with the send class, but that would work just as well. Will add a example. – Scott Chamberlain Nov 24 '10 at 19:34
  • 2
    @Andreas Niedermair, One advantage to creating a separate background worker thread is you can dispose of the objects as soon as they are done instead of waiting for the GC to do it (both `MailMessage` and `StmpClient` implment `IDisposeable`) – Scott Chamberlain Nov 24 '10 at 19:51
  • ah yes ... i forogt the details about GC :) –  Nov 25 '10 at 06:52