so im trying to delay the sending of email from my program.
In order to keep the UI interactive, i started a new thread and called the email method in the thread. It works. It sends the emails. However i cant figure out how to sleep the thread.
Ive tried using Thread.sleep() in the actual email method, but it doesnt seem to work.
Thread oThread = new Thread(new ThreadStart(() => { sendEMailThroughOUTLOOK(recipientAddress, subjectLine, finalbody); }));
oThread.Start();
email method..
public void sendEMailThroughOUTLOOK(string recipient, string subject, string body)
{
Thread.Sleep(60000);
try
{
// Create the Outlook application.
Outlook.Application oApp = new Outlook.Application();
// Create a new mail item.
Outlook.MailItem oMsg = (Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
// Set HTMLBody.
//add the body of the email
oMsg.Body = body;
oMsg.Subject = subject;
// Add a recipient.
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
// Change the recipient in the next line if necessary.
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(recipient);
oRecip.Resolve();
// Send.
oMsg.Send();
// Clean up.
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
}//end of try block
catch (Exception ex)
{
}//end of catch
//end of Email Method
}
There is nothing apparently wrong with the code you've posted. However, thread.Suspend() is a very old API = it has been deprecated/obsoleted since .NET 2.0, as it's not safe to do this.
The static method Thread.Sleep(N) most certainly suspends the calling thread for N milliseconds.
To clarify; calling Thread.Sleep suspends the calling thread, so in your example code, where you have;
public void sendEMailThroughOUTLOOK(string recipient, string subject, string body)
{
Thread.Sleep(60000);
...
}
The call to Thread.Sleep(60000) is suspending the thread which is executing the method sendEMailThroughOUTLOOK. And since you appear to be calling that method in it's own thread,as evidenced by;
Thread oThread = new Thread(new ThreadStart(() => { sendEMailThroughOUTLOOK(recipientAddress, subjectLine, finalbody); }));
oThread.Start();
the correct thread should be suspended.
There is no way to do something like this;
Thread t = new Thread();
t.Start();
t.Sleep(60000);
You can start, or kill a running thread, but not sleep/suspend it. As noted - this API was deprecated as it is not a safe way to implement thread synchronisation (see http://msdn.microsoft.com/en-us/library/system.threading.thread.suspend%28v=vs.71%29.aspx for an explanation of why this is not a good idea).
Since you are a bit new to programming I won't try to explain all the relevant details but I thought it was cool that you showed me a new trick with your sample so I wanted to help you out if I could.
This isn't the only way to code this but I can tell you this is a reasonable one. It uses a background worker component to keep the UI responsive while sending the email. Note the use of the background worker's provided events DoWork and RunWorkerCompleted. The setup for these events took place in the designer which is why I zipped the solution up for you so you could take a look at the whole thing (I did so with google Drive and this is my first attempt doing a public share - if the link opens for you like it does for me, you'll get a File menu from which you can select Download).
I created an inner private class and passed it to the background worker. I do this because I don't want to access the data in my UI components from code running in a different thread. This will not always cause a problem but I find it to be a good practice in general. Also, it makes it so if I want to refactor the code later it will be easier to take the lines from DoWork and put them somewhere else without any fuss.
On the more general area of multi threaded programming - it's a multi faceted subject and you don't need to get it all right away. This is my favorite tutorial (the book is great too).
using System;
using System.ComponentModel;
using System.Windows.Forms;
using Outlook = Microsoft.Office.Interop.Outlook;
namespace Emailer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void SendButton_Click(object sender, EventArgs e)
{
this.sendEmailBackgroundWorker.RunWorkerAsync(new _Email
{
Recipient = this.recipientTextBox.Text,
Subject = this.subjectTextBox.Text,
Body = this.emailToSendTextBox.Text
});
}
private class _Email
{
public string Body { get; set; }
public string Subject { get; set; }
public string Recipient { get; set; }
}
private void sendEmailBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var email = (_Email)e.Argument;
try
{
Outlook.Application oApp = new Outlook.Application();
Outlook.MailItem oMsg = (Microsoft.Office.Interop.Outlook.MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
oMsg.Body = email.Body;
oMsg.Subject = email.Subject;
Outlook.Recipients oRecips = (Outlook.Recipients)oMsg.Recipients;
Outlook.Recipient oRecip = (Outlook.Recipient)oRecips.Add(email.Recipient);
oRecip.Resolve();
oMsg.Send();
oRecip = null;
oRecips = null;
oMsg = null;
oApp = null;
}
catch (Exception ex)
{
e.Result = ex;
}
e.Result = true;
}
private void sendEmailBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string message;
if (e.Result is Exception)
message = "Error sending email: " + (e.Result as Exception).Message;
else if (e.Result is bool && (bool)e.Result)
message = "Email is sent";
else
throw new Exception("Internal Error: not expecting " + e.Result.GetType().FullName);
MessageBox.Show(message);
}
}
}
Related
I have a WPF application that has a part where the users fill out basically an outlook-like form and then it populates an Outlook Email with the appropriate information. The problem is that while this email is open, code execution stops until the email is either sent or closed.
I am attempting to put it on a new thread but I am running into all kinds of problems in various places with getting this to work. The "body" of the email form is a rich text box and needs to be formatted prior to putting it into the Outlook email for it to show up properly.
From what I read the Clipboard calls must be put on their own STA threads, but then it returns null before they finish.
How can I get this working properly? Basically all I want is for the Outlook Email Item to be on its own thread so it doesn't block execution of the main thread while its open.
private async Task CreateEmail()
{
try
{
//create an outlook object
await Task.Run(() =>
{
MyOutlook.Application oApp = new MyOutlook.Application();
//we need to check the to strings of that various items and join them together
var toStrings = emailForm.ToMain;
toStrings += String.IsNullOrEmpty(emailForm.ToRM) ? "" : ";" + emailForm.ToRM;
toStrings += String.IsNullOrEmpty(emailForm.ToSM) ? "" : ";" + emailForm.ToSM;
MyOutlook.MailItem oMailItem = (MyOutlook.MailItem)oApp.CreateItem(MyOutlook.OlItemType.olMailItem);
oMailItem.To = toStrings;
oMailItem.CC = emailForm.CC;
oMailItem.BCC = emailForm.BCC;
oMailItem.Subject = emailForm.Subject;
oMailItem.RTFBody = GetRTBText();
oMailItem.Display(true);
});
}
catch(Exception ex)
{
ErrorWindow errWin = new ErrorWindow("There was an error creating the Outlook Email! Error: " + ex.Message);
errWin.Show();
}
}
private byte[] GetRTBText()
{
byte[] RTFArr = null;
//need to create a new STA Thread for the clipboard
Thread thread = new Thread(() => Clipboard.Clear());
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
this.Dispatcher.Invoke(() =>
{
RTBBody.SelectAll();
RTBBody.Copy();
});
Thread thread2 = new Thread(() => RTFArr = Encoding.UTF8.GetBytes (Clipboard.GetText(TextDataFormat.Rtf)));
thread2.SetApartmentState(ApartmentState.STA);
thread2.Start();
thread.Join();
return RTFArr;
}
Do not call Display(true) - that will display the message modally. Call Display(false).
I have a console app thats sends mails within a thread.
in this thread method I have a loop that semds emails to each recipient.
I am having issues where as I am trying to send multiple emails before the previous ones have had the chance to get sent.
my code:
foreach(var m in mailModel.Recipients)
{
Mailmanager.SendMessageS(mailModel.DomainName, mailModel.Severity, DateTime.Now, m);
}
And the send method:
public static async Task SendMessageS(string domainName, ErrorSeverity severity, DateTime errorTime, Recipient recipient)
{
try
{
string error = "";
string fromEmail = "OwerWatch#mydomain.com";
string toEmail = recipient.SendEmailTo;
MailMessage message = new MailMessage(fromEmail, toEmail);
Guid guid = Guid.NewGuid();
SmtpClient smtpClient = new SmtpClient(server, port);
/*if (_useAuthentication)*/
smtpClient.Credentials = new NetworkCredential("", "");
smtpClient.EnableSsl = false;
//mail.Subject = subject;
//mail.Body = body;
message.Subject = "Problem ( " + severity + ") " + domainName;
message.Body = BuildMessage(error, recipient.RecipientName, domainName, errorTime, severity);
smtpClient.SendCompleted += SendCompletedCallback;
await smtpClient.SendMailAsync(fromEmail, toEmail, message.Subject, message.Body /* user state, can be any object*/);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
I am getting this warrning:
because this call is not awaited execution of the current method
continues before the call is completed. Consider applying the await
opeartor to the result of the call
I understand the warrning but I can't figure out how I can accomplish this since I have a loop that goes through all my recipients.
How can I do this correctly?
This is a quick fix (added await keyword on your call to Mailmanager.SendMessageS), since your utility method is working doing async operation.
foreach(var m in mailModel.Recipients)
{
await Mailmanager.SendMessageS(mailModel.DomainName, mailModel.Severity, DateTime.Now, m);
}
There might be better ways to do it as an overall process.
The best thing to do here is to use a queue.
You should add all your messages to a queue and than process them one by one, even with multiple threads, if you want.
Check this answer for a couple of examples.
I'm trying to send confirmation mails to users periodically in ASP.NET.
To do this I polulate a queue with mails and check it every 30 seconds. Any confirmation emails in the queue at this time are sent and then cleared from the queue.
Does anyone know how to do this?
Here is my sending mail code
public static bool SendMail(string AdminMail,string AdminPassword,string subject,string toAddress, string content,DateTime SendTime)
{
toAddressListProperty.Enqueue(toAddress);
if(date==null)
{
date = DateTime.Now.Second;
}
if (date-SendTime.Second > 120)
{
var message = new MailMessage
{
From = new MailAddress(AdminMail)
};
foreach (var toAddressl in toAddressListProperty)
{
message.To.Add(new MailAddress(toAddressl));
}
message.Subject = subject;
message.Body = content;
message.IsBodyHtml = true;
var smtp = new SmtpClient
{
Credentials = new System.Net.NetworkCredential(AdminMail, AdminPassword),
Port = 587,
Host = "smtp.gmail.com",
EnableSsl = true
};
smtp.Send(message);
//date = SendTime;
return true;
}
return false;
}
I have done this using a background thread. I did a little research, and I believe this is an ok approach. There are a few dangers, which this blog details.
The main thing is to ensure you never throw an exception from a background thread, as I believe that will cause the web process to restart. Also, incase the thread dies, I ensure it is running on every call.
I have been using this approach for a few months, and so far no issues.
Also I run it every 1 second, this minamizes the amount of time you might loose emails due to an app shutdown.
public class BackgroundSmtpService
{
private ILog _log = LogManager.GetLogger(typeof(BackgroundSmtpService));
private readonly SmtpService SmtpService;
private static Thread _watchThread;
private static List<Email> _emailToSend = new List<Email>();
public BackgroundSmtpService(SmtpService smtpService)
{
SmtpService = smtpService;
}
public void Send(Email email)
{
lock (_emailToSend)
{
_emailToSend.Add(email);
}
EnsureRunning();
}
private void EnsureRunning()
{
if (_watchThread == null || !_watchThread.IsAlive)
{
lock (SmtpService)
{
if (_watchThread == null || !_watchThread.IsAlive)
{
_watchThread = new Thread(ThreadStart);
_watchThread.Start();
}
}
}
}
private void ThreadStart()
{
try
{
while (true)
{
Thread.Sleep(1000);
try
{
lock (_emailToSend)
{
var emails = _emailToSend;
_emailToSend = new List<Email>();
emails.AsParallel().ForAll(a=>SmtpService.Send(a));
}
}
catch (Exception e)
{
_log.Error("Error during running send emails", e);
}
}
}
catch (Exception e)
{
_log.Error("Error during running send emails, outer", e);
}
}
}
You might want to consider using Quartz.net library. It have decent documentation and it's fairly easy to use.
The biggest challenge you'll have with this is that any time your application pool recycles it will take a new request to kick stats your "timer". If you had an HTTP monitor application such as Pingdom to poll your server it shouldn't be a problem, but then again you could also just use a third party monitor tool to hit your a page on your site every N seconds that would send out the mail and issue a response.
I myself would use a Windows service to pull a queue from a database and send out messages that way.
Easiest way is to create a VBScript that sends an HTTP GET request to http://localhost/SendConfirmationEmails.aspx
You'd start the VBScript in your global.asax Application_Start method.
The SendConfirmationEmails.aspx would act as a simple web service (you could use an ashx, or actual web service asmx if you wanted). It would only be accessible on the localhost so remote users wouldn't be able to spam it.
Using a windows service is probably the best practice method, but a simple VBScript will get the job done.
surl="http://localhost/SendConfirmationEmails.aspx"
set oxmlhttp=createobject("msxml2.xmlhttp")
with oxmlhttp
.open "GET",surl,false
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.send srequest
end with
You'd put the code above in a while wend loop with a Sleep to delay every 30 seconds...
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!
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)...
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");
}
}
I'm developing an application where a user clicks/presses enter on a certain button in a window, the application does some checks and determines whether to send out a couple of emails or not, then show another window with a message.
My issue is, sending out the 2 emails slows the process noticeably, and for some (~8) seconds the first window looks frozen while it's doing the sending.
Is there any way I can have these emails sent on the background and display the next window right away?
Please don't limit your answer with "use X class" or "just use X method" as I am not all too familiarized with the language yet and some more information would be highly appreciated.
Thanks.
As of .NET 4.5 SmtpClient implements async awaitable method
SendMailAsync.
As a result, to send email asynchronously is as following:
public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
var message = new MailMessage();
message.To.Add(toEmailAddress);
message.Subject = emailSubject;
message.Body = emailMessage;
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendMailAsync(message);
}
}
As it's a small unit of work you should use ThreadPool.QueueUserWorkItem for the threading aspect of it. If you use the SmtpClient class to send your mail you could handle the SendCompleted event to give feedback to the user.
ThreadPool.QueueUserWorkItem(t =>
{
SmtpClient client = new SmtpClient("MyMailServer");
MailAddress from = new MailAddress("me#mydomain.com", "My Name", System.Text.Encoding.UTF8);
MailAddress to = new MailAddress("someone#theirdomain.com");
MailMessage message = new MailMessage(from, to);
message.Body = "The message I want to send.";
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Subject = "The subject of the email";
message.SubjectEncoding = System.Text.Encoding.UTF8;
// Set the method that is called back when the send operation ends.
client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
// The userState can be any object that allows your callback
// method to identify this send operation.
// For this example, I am passing the message itself
client.SendAsync(message, message);
});
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Get the message we sent
MailMessage msg = (MailMessage)e.UserState;
if (e.Cancelled)
{
// prompt user with "send cancelled" message
}
if (e.Error != null)
{
// prompt user with error message
}
else
{
// prompt user with message sent!
// as we have the message object we can also display who the message
// was sent to etc
}
// finally dispose of the message
if (msg != null)
msg.Dispose();
}
By creating a fresh SMTP client each time this will allow you to send out emails simultaneously.
It's not too complicated to simply send the message on a separate thread:
using System.Net.Mail;
Smtp.SendAsync(message);
Or if you want to construct the whole message on the separate thread instead of just sending it asynchronously:
using System.Threading;
using System.Net.Mail;
var sendMailThread = new Thread(() => {
var message=new MailMessage();
message.From="from e-mail";
message.To="to e-mail";
message.Subject="Message Subject";
message.Body="Message Body";
SmtpMail.SmtpServer="SMTP Server Address";
SmtpMail.Send(message);
});
sendMailThread.Start();
SmtpClient.SendAsync Method
Sample
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.ComponentModel;
namespace Examples.SmptExamples.Async
{
public class SimpleAsynchronousExample
{
static bool mailSent = false;
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Get the unique identifier for this asynchronous operation.
String token = (string) e.UserState;
if (e.Cancelled)
{
Console.WriteLine("[{0}] Send canceled.", token);
}
if (e.Error != null)
{
Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
} else
{
Console.WriteLine("Message sent.");
}
mailSent = true;
}
public static void Main(string[] args)
{
// Command line argument must the the SMTP host.
SmtpClient client = new SmtpClient(args[0]);
// Specify the e-mail sender.
// Create a mailing address that includes a UTF8 character
// in the display name.
MailAddress from = new MailAddress("jane#contoso.com",
"Jane " + (char)0xD8+ " Clayton",
System.Text.Encoding.UTF8);
// Set destinations for the e-mail message.
MailAddress to = new MailAddress("ben#contoso.com");
// Specify the message content.
MailMessage message = new MailMessage(from, to);
message.Body = "This is a test e-mail message sent by an application. ";
// Include some non-ASCII characters in body and subject.
string someArrows = new string(new char[] {'\u2190', '\u2191', '\u2192', '\u2193'});
message.Body += Environment.NewLine + someArrows;
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Subject = "test message 1" + someArrows;
message.SubjectEncoding = System.Text.Encoding.UTF8;
// Set the method that is called back when the send operation ends.
client.SendCompleted += new
SendCompletedEventHandler(SendCompletedCallback);
// The userState can be any object that allows your callback
// method to identify this send operation.
// For this example, the userToken is a string constant.
string userState = "test message1";
client.SendAsync(message, userState);
Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.");
string answer = Console.ReadLine();
// If the user canceled the send, and mail hasn't been sent yet,
// then cancel the pending operation.
if (answer.StartsWith("c") && mailSent == false)
{
client.SendAsyncCancel();
}
// Clean up.
message.Dispose();
Console.WriteLine("Goodbye.");
}
}
}
Just because this is a little vague...I will be brief...
There are a lot of ways to do asynchronous or parallel work in c#/.net etc.
The fastest way to do what you want is to use a background worker thread which will avoid locking up your UI.
A tip with background worker threads : you cannot directly update the UI from them (thread affinity and Marshalling is just something you learn to deal with...)
Another thing to consider...if you use the standard System.Net.Mail type stuff to send the emails...be careful how you craft your logic. If you isolate it all in some method and call it over and over, it will likely have to tear down and rebuild the connection to the mail server each time and the latency involved in authentication etc will still slow the whole thing down unnecessarily. Send multiple e-mails through a single open connection to the mail server when possible.
Here is a fire and forget approach together with async using .Net 4.5.2+:
BackgroundTaskRunner.FireAndForgetTaskAsync(async () =>
{
SmtpClient smtpClient = new SmtpClient(); // using configuration file settings
MailMessage message = new MailMessage(); // TODO: Initialize appropriately
await smtpClient.SendMailAsync(message);
});
where BackgroundTaskRunner is:
public static class BackgroundTaskRunner
{
public static void FireAndForgetTask(Action action)
{
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => // .Net 4.5.2+ required
{
try
{
action();
}
catch (Exception e)
{
// TODO: handle exception
}
});
}
/// <summary>
/// Using async
/// </summary>
public static void FireAndForgetTaskAsync(Func<Task> action)
{
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => // .Net 4.5.2+ required
{
try
{
await action();
}
catch (Exception e)
{
// TODO: handle exception
}
});
}
}
Works like a charm on Azure App Services.
Try this:
var client = new System.Net.Mail.SmtpClient("smtp.server");
var message = new System.Net.Mail.MailMessage() { /* provide its properties */ };
client.SendAsync(message, null);
What you want to do is run the e-mail task on a separate thread so the main code can continue processing while the other thread does the e-mail work.
Here is a tutorial on how to do that:
Threading Tutorial C#
Use the SmtpClient class and use the method SendAsync in the System.Net.Mail namespace.
Using the Task Parallel Library in .NET 4.0, you can do:
Parllel.Invoke(() => { YourSendMailMethod(); });
Also, see cristina manu's blog post about Parallel.Invoke() vs. explicit task management.
i think this is the best way :
public async Task Send(string to, string subject, string body)
{
MailMessage mail = new MailMessage();
SmtpClient SmtpServer = new SmtpClient("smtp.mail.yahoo.com");
mail.From = new MailAddress("yourEmail#email.com", "sender name");
mail.To.Add(to);
mail.Subject = subject;
mail.Body = body;
mail.IsBodyHtml = true;
SmtpServer.Port = 587;
SmtpServer.Credentials = new System.Net.NetworkCredential("yourEmail#email.com", "your key");
SmtpServer.EnableSsl = true;
await Task.Run(() =>
{
SmtpServer.SendAsync(mail, null);
});
}