1

I have a problem, I'm trying send a mail using one structure like this one:

private void SendMail()
{

    var client = new SmtpClient("smtp.gmail.com", 587)
    {
        Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
        EnableSsl = true
    };
    client.Send("mymail@mail.com", "AdressClient@mail.com", "Subject", "Body");
}

Well, this structure works just fine, but cause a lag in my main program, for that reason I woudl like to execute the SendMail function in another Thread, like this:

private void ButtonTestSendMail_Click(object sender, EventArgs e)
    {
        //THREAD
        Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail));
        ThreadSendEmail .IsBackground = true;
        ThreadSendEmail .Start();
    }


private void SendMail()
{   
   var client = new SmtpClient("smtp.gmail.com", 587)
   {
      Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
      EnableSsl = true
   };
   client.Send("mymail@mail.com", "AdressClient@mail.com", "Subject", "Body");
}

Well at this point I notice that I need to change the parameters of the mail, like, AdressClient@mail.com, Suject and Body.

But I don't know How :/

How Can I write a thread that accepte parameters, something like this:

private void ButtonTestSendMail_Click(object sender, EventArgs e)
        {
            string Body = "BodyTest";
            string AdressMail = "AdressMail@test.com";
            string Subject = "SubjectTest";
        //THREAD
        Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail(Body,AdressMail,Subject));
        ThreadSendEmail .IsBackground = true;
        ThreadSendEmail .Start();
    }


    private void SendMail(string Body, string Adress, string Subject)
    {   
       var client = new SmtpClient("smtp.gmail.com", 587)
       {
          Credentials = new NetworkCredential("mymail@mail.com", "mypassword"),
          EnableSsl = true
       };
       client.Send("mymail@mail.com", Adress, Subject, Body);
    }

I tried but doesnt work, I have a MethodName Expected and a notification that the ERROR is in this line:

Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail(Body,AdressMail,Subject));

How Can I write a thread that accepte parameters? Thank you for help! Best Regards!

Vanderley Maia
  • 465
  • 5
  • 7

4 Answers4

2

You're almost there:

Thread ThreadSendEmail = new Thread(() => this.SendMail(Body,AdressMail,Subject));

The lambda does the trick. You can't invoke SendMail directly, you want to pass it as an uninvoked function.

Be aware that the thread will be rudely aborted if your ASP.NET process recycles (maybe because you're deploying). The mail will then be lost.

usr
  • 168,620
  • 35
  • 240
  • 369
2

If all you need to do is send a mail message asynchronously, you can use the SmtpClient.SendAsync method and your calling thread will not be blocked (http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx).

But if you really want a new thread do to the job, you need to create a class wich contais your parameters values and instanciate it using the ParameterizedThreadStart delegate. Here is a SO entry with one sample: ThreadStart with parameters

Community
  • 1
  • 1
Fabiano Salles
  • 270
  • 2
  • 10
1

It's often not necessary, and sometimes a bad idea, to explicitly create your own thread. Instead, you can leverage the .NET ThreadPool to kick off the work on an existing, but non-main thread. For example:

ThreadPool.QueueUserWorkItem(state => { /* threadpool work */ }, null);

Either way you go, working on another thread can be hazardous because if any exceptions are thrown (and not caught) your app will terminate. Also, the only effect Thread.IsBackground = true has is to not block your app from exiting if it's running. If your intent is to change thread priority you should set a different property.

If you're using .NET 4.0, you can use a higher level abstraction that helps you with exceptions:

Task task = Task.Factory.StartNew(() => { /* threadpool work */ });

Later, if an exception was thrown within the task, you can observe it and react as necessary using the various properties and methods on the Task object. On .NET 4.0, if you don't observe the exception but just let the task get GC'd, it will also crash your app (although at a non-deterministic time, whenever the Finalizer runs). On .NET 4.5, your app will not crash in this scenario.

Finally, if you're using .NET 4.5, you can get even shorter:

Task task = Task.Run(() => { /* threadpool work */ });
Andrew Arnott
  • 80,040
  • 26
  • 132
  • 171
0

The Thread.Start() method has an overload with a second object parameter that is passed to the thread method - so you can do:

Thread ThreadSendEmail = new Thread(new ThreadStart(this.SendMail));
ThreadSendEmail.IsBackground = true;
ThreadSendEmail.Start("Body test");

. . . .

private void SendMail(object data)
{
  string body = (string)data;
  . . . 
}

If you want/need to pass more parameters bundle them in an object, and pass that object.

Instead than creating a thread you can use the thread pool, that scales better and it is easier to use, just one line of code:

ThreadPool.QueueUserWorkItem(new WaitCallback(SemdMail), "Body test");

P.S. this is the 'old style' solution, the 'modern' solution is to use lambdas - see @usr answer.

MiMo
  • 11,793
  • 1
  • 33
  • 48
  • I'd argue that since the arrival of delegates in .NET 2.0 you don't need to use the awkward state parameter anymore. – usr Mar 02 '13 at 22:21