Reputation: 732
I try to send mail and i don't want to wait for the result , i create new thread and send the mail its working on my pc but when i build the application and upload it to shared hosting its taking to match time like no new thread created and mail send successfully .
Thread sendMailThread = new Thread(() =>
sendMail(to, body, subject));
sendMailThread.Start();
public bool sendMail(string to, string body,string subject)
{
try
{
SmtpClient client = new SmtpClient(smtpServer);
//If you need to authenticate
client.Port = smtpPort;
client.EnableSsl = enableSsl;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(smtpUser, smtpPass);
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(defaultSender);
mailMessage.To.Add(to);
mailMessage.Subject = subject;
mailMessage.Body = body;
client.Send(mailMessage);
return true;
}
catch(Exception ex)
{
return false;
}
}
update controller action
[System.Web.Http.HttpGet]
public void changePassword(string userId, string newPassword)
{
var context = new ApplicationDbContext();
UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser cUser = userManager.FindById(userId);
if (String.IsNullOrEmpty(newPassword)) newPassword = "123456";
String hashedNewPassword = userManager.PasswordHasher.HashPassword(newPassword);
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();
store.SetPasswordHashAsync(cUser, hashedNewPassword);
store.UpdateAsync(cUser);
context.SaveChanges();
string mailBody = "Your password has been changed with user name : " + cUser.UserName + " and password: " + newPassword;
//send mail
mailService.sendMailThread(cUser.Email, mailBody, "Your password has been changed");
}
update why i need to send mail in new thread ? i wan't want response wait until mail send , as it take some time .
update this code is working perfect on my local machine with the same SMTP server , but when i upload the site to shared hosting the request taking match time until its returned to browser , and i think send mail blocking my main request thread .
Upvotes: 0
Views: 971
Reputation: 131180
First, you don't need a separate thread to send an email asynchronously. You can use SenMailAsync, eg:
public async Task<bool> sendMailAsync(string to, string body,string subject)
{
...
await client.SendMailAsync(mailMessage);
...
}
public async Task MyAction(...)
{
...
var success=await sendMailAsync(to,body,subject);
if(!success)
{
Log.Error("Sending failed but I don't know why because I discarded the exception");
}
...
}
That won't make sending faster though, it means that you don't have to block the request thread while waiting for sending to complete. Using a separate thread won't complete faster either. After all, the remote server won't work faster if you use the request thread or another thread.
In fact, if you use a background thread and wait for it to complete, you harm performance. The request thread will be blocked waiting for another thread to do what the request thread could do as easily. With await
the request thread is released and execution resumes after await
.
Web sites and applications typically use a local smtp server or even IIS's SMTP service to send emails immediatelly and avoid waiting for responses from remote servers. You could build a queue to send emails asynchronously, but that's exactly what the SMTP service does in the first place.
UPDATE
If you can't use an SMTP Service and don't won't to wait for the send operation, you'll have to create a fire-and-forget action in a safe way. Simply using a Thread, or removing await
isn't enough. ASP.NET can recycle an AppDomain for any number of reasons, terminating your thread/task with it. Scott Hanselman explains the various techniquest used to run a background task safely. One of them is to tell ASP.NET that you have a background task, with QueueBackgroundWorkItem. IIS will wait up to 90 seconds for a background task to terminate before recycling.
To register a background email task :
public async Task MyAction(...)
{
...
HostingEnvironment.QueueBackgroundWorkItem(ct =>sendMailAsync(to,body,subject));
...
}
Upvotes: 2
Reputation: 2085
We had similar problems. They were usually caused by one of the following reasons
that means usually the client code itself wasn't really the problem.
You could check the port on which you connect to your SMTP Server and try sending it with and without an SSL connection.
Or you can, as mentioned by others, send your mails asynchronously. Either use some BackgroundWorker
, Task
, just fire and forget (probably not an ideal solution) or by using a fullfledged framework like hangfire
I think the error/problem is not in your code but somewhere in the communication between shared hosting and your SMTP Server.
Upvotes: 0
Reputation: 571
public void SendAsyncMail()
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress("Enter from mail address");
mail.To.Add(new MailAddress("Enter to address #1"));
mail.To.Add(new MailAddress("Enter to address #2"));
mail.Subject = "Enter mail subject";
mail.Body = "Enter mail body";
SmtpClient smtpClient = new SmtpClient();
Object state = mail;
//event handler for asynchronous call
smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);
try
{
smtpClient.SendAsync(mail, state);
}
catch (Exception ex) { /* exception handling code here */ }
}
void smtpClient_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
MailMessage mail = e.UserState as MailMessage;
if (!e.Cancelled && e.Error!=null)
{
message.Text = "Mail sent successfully";
}
}
Upvotes: 0