I don't want the user to wait for page completing the sending processes, so I'm thought of using SendAsync in ASP.NET 3.5. But for after debuging, I found that the Main Thread still waits.
Main: Call send email function...
mailSend: Configuring....
mailSend: setting up incorrect port....
mailSend: Attempt now to send....
mailSend: End of Line
Main: Email Function call finish.
Main: Proccess Complete!
mailComp: Sending of mail failed, will try again in 5 seconds...
mailComp: Retrying...
mailComp: Send successful!
mailComp: End of Line
Now the I placed incorrect port setting so the first email fails, and test to see if the second time it will be successful. Even with the correct port, the page still waits. Only after mailComp function is finish is when the Page is finally posted. Is this some limitation to SendAsyn?
And here some code, not sure if this will be helpful.
protected void btnReset_Click(object sender, EventArgs e)
{
try
{
DataContext db = new DataContext();
var query = from u in db.Fish
where u.Username == txtUsername.Text & u.Email == txtEmail.Text
select new { u.Username, u.Email };
if (query.Count() != 0)
{
User user = new User();
String token = user.requestPasswordReset(txtUsername.Text);
String URL = Request.Url.AbsoluteUri.ToString() + "?token=" + token;
String body = "Reseting you password if you \n" + URL + "\n \n ";
Untilty.SendEmail(txtEmail.Text, "Reseting Password", body);
litTitle.Text = "Message was sent!";
litInfo.Text = "Please check your email in a few minuets for further instruction.";
viewMode(false, false);
}
else
{
litCannotFindUserWithEmail.Visible = true;
}
}
catch (Exception ex)
{
Debug.Write("Main: Exception: " + ex.ToString());
litInfo.Text = "We are currently having some technically difficulty. Please try again in a few minuets. If you are still having issue call us at 905344525";
}
}
///
public static class Utility
///
public static void SendEmail(string recipient, string subject, string body)
{
MailMessage message = new MailMessage();
message.To.Add(new MailAddress(recipient));
message.From = new MailAddress(fromaddress, "Basadur Profile Website");
message.Subject = subject;
message.Body = body;
Send(message);
}
private static void Send(MailMessage msg)
{
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.Credentials = new System.Net.NetworkCredential(fromaddress, mailpassword);
smtp.EnableSsl = true;
Debug.WriteLine("mailSend: setting up incorrect port....");
smtp.Port = 5872; //incorrect port
smtp.SendCompleted += new SendCompletedEventHandler(smtp_SendCompleted);
smtp.SendAsync(msg, msg);
}
static void smtp_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
var msg = (MailMessage)e.UserState;
if (e.Error != null)
{
System.Threading.Thread.Sleep(1000 * 5);
try
{
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.Credentials = new System.Net.NetworkCredential(fromaddress, mailpassword);
smtp.EnableSsl = true;
smtp.Port = 587;
smtp.Send(msg);
}
catch (Exception ex)
{
Debug.WriteLine("mailComp: Failed for the second time giving up.");
}
}
}
In .NET 4.5.2, a method was added for scheduling tasks in the background, independent of any request: HostingEnvironment.QueueBackgroundWorkItem().
HostingEnvironment.QueueBackgroundWorkItem() is in the System.Web.Hosting namespace.
The remarks in the documentation say:
Differs from a normal ThreadPool work item in that ASP.NET can keep
track of how many work items registered through this API are currently
running, and the ASP.NET runtime will try to delay AppDomain shutdown
until these work items have finished executing.
Meaning, you can fire off a task in a fire-and-forget manner with a greater confidence in it not being terminated when the app domain recycles.
Usage is like:
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
try
{
// do work....
}
catch(Exception)
{
//make sure nothing can throw in here
}
});
These days you can use a Task to dispatch work to the thread pool. Just use
Task.Run(()=> Untilty.SendEmail(txtEmail.Text, "Reseting Password", body));
The debugger seems to force things to be single threaded. If you step through, you may find that you end up jumping between two different files, as each step moves a different thread.
Try to add some logging in there and run without debugging.
Using the below code you can send async emails in asp.net with SmtpClient.
ThreadPool.QueueUserWorkItem(callback =>
{
var mailMessage = new MailMessage
{
...
};
//if you need any references in handlers
object userState = new ReturnObject
{
MailMessage = mailMessage,
SmtpClient = smtpServer
};
smtpServer.SendCompleted += HandleSmtpResponse;
smtpServer.SendAsync(mailMessage, userState);
});
Use threading:
// Create the thread object, passing in the method
// via a ThreadStart delegate. This does not start the thread.
Thread oThread = new Thread(new ThreadStart(SendMyEmail));
// Start the thread
oThread.Start();
Here is the source, it has a full threading tutorial.
Related
I have a mailer and here is the code:
private static int i=0;
protected void btnSubmit_Click(object sender, EventArgs e)
{
++i; //i want to increment this variable
{
SendHTMLMail();
}
void SendHTMLMail()
{
StreamReader reader = new StreamReader(Server.MapPath("~/one.html"));
string readFile = reader.ReadToEnd();
string myString = "";
myString = readFile;
MailMessage Msg = new MailMessage();
Msg.From = new MailAddress(txtUsername.Text);
Msg.To.Add(txtTo.Text);
Msg.Subject = txtSubject.Text;
Msg.Body = myString.ToString();
Msg.IsBodyHtml = true;
if (fuAttachment.HasFile)
{
string FileName = Path.GetFileName(fuAttachment.PostedFile.FileName);
Msg.Attachments.Add(new Attachment(fuAttachment.PostedFile.InputStream, FileName));
}
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential(txtUsername.Text, txtpwd.Text);
smtp.EnableSsl = true;
smtp.Send(Msg);
Msg = null;
ClientScript.RegisterStartupScript(GetType(), "alert", "alert('Email sent.');", true);
// Request both failure and success report
Msg.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure | DeliveryNotificationOptions.OnSuccess;
int emailsSent = 0;
try
{
Console.WriteLine("start to send email ...");
smtp.Send(Msg);
emailsSent++;
Console.WriteLine("email was sent successfully!");
}
catch (Exception ex)
{
Console.WriteLine("failed to send email with the following error:");
Console.WriteLine(ex.Message);
}
}
}
in the above code, i have a variable 'i' and i want to increment it every time i send the mail. Now the problem i am facing is that 'i' is getting incremented only when i am sending mail again and again when my aspx page in localhost is opened. As soon as i close my aspx page, re-opens it and send the mail again, then the variable 'i' is again getting incremented to one and not to say 4 or 5.
Behavior changes where you put this code. If it's in ASPX pages, you'll loose static data whenever runtime recompile that page. If it's in DLL files, you'll loose values whenever application/IIS Pool recycles. You need to save final values into a persistent store (ie Database). Next time you need them, you must retrieve from DB, increment it then save again.
Be careful, web applications are multi-thread and static variables are not thread safe. If two threads modify same variable at the same time you'll run into chaos. Use locking mechanism to access static variables in multi-threaded applications.
You need to define a separate static class for it- (because if you hit refresh / reload page in asp.net life cycle the entire page gets reloaded along with the objects.)
Define a static class (or a non static class with its constructor called) with variable/property to be incremented every time you send mail.
public static class Mail
{
private static int mailCount;
public static void MailSent()
{
mailCount++;
}
public static int GetMailCount()
{
return mailCount;
}
}
Now in your button click use the static methods to increment and retrieve of mailCount-
protected void btnSubmit_Click(object sender, EventArgs e)
{
Mail.MailSent(); // increments every time you send mail
// to check how many mails sent in debug console
System.Diagnostics.Debug.WriteLine(Mail.GetMailCount());
//... YOU MAILING CODE
}
Does anyone know how i would code this:
to send an email to the admin/manager everyday at a specific time including a table from the database (Stock Table - which only has four pieces of stock) so they will be informed of their stock levels and if they need to reorder.
Or else
Something in which will send an email to the manager/ admin if one of these four stock levels are low informing them a certin materials/ piece of stock has reached the minimum level and to re order.
I have the code for sending an email:
protected void Button1_Click1(object sender, EventArgs e)
{
MailMessage mail = new MailMessage(from.Text, to.Text, subject.Text, body.Text);
SmtpClient Client = new SmtpClient(smtp.Text);
Client.Port = 587;
Client.Credentials = new System.Net.NetworkCredential(username.Text, password.Text);
Client.EnableSsl = true;
Client.Send(mail);
Response.Write("<script LANGUAGE='JavaScript' >alert('Mail Sent')</script>");
}
any help is welcomed!!!
Thank you!
You need a scheduler so you can schedule a daily task to check the stock levels and send an email if needed. You can achieve this using hangfire if you want to keep everything inside your asp.net application. Hangfire is a scheduler. Check https://www.hangfire.io/
The code would look like this
RecurringJob.AddOrUpdate(
() => {
//TODO: Check your Stock Table DB
var from = "noreply#<yourcompany>.com"
var to = "admin#<yourcompny>.com"
var subject = "Low stock"
var body = "The following items are low in stock : "
// TODO: append items to body variable
MailMessage mail = new MailMessage(from, to, subject, body);
SmtpClient Client = new SmtpClient(smtp.Text);
Client.Port = 587;
Client.Credentials = new System.Net.NetworkCredential(username.Text, password.Text);
Client.EnableSsl = true;
Client.Send(mail);},
Cron.Daily);
});
use Windows Service to Monitoring the data, hour and DB.
private void mainTimer_Tick(object sender, EventArgs e)
{
try
{
if (ConfigsHTM["exechour"] != null)
{
if (DateTime.Now.ToString("HH:mm:ss") == ConfigsHTM["exechour"].ToString())
{
ClassProcessing clsProc = new ClassProcessing();
clsProc.StartDate = DateTime.Now.AddDays(-1);
clsProc.EndDate = DateTime.Now.AddDays(-1);
clsProc.ProcessAll();
if (StatusHTM.Count > 0)
StatusHTM.Clear();
StatusHTM.Add("locationstatus","Todas as Unidades");
StatusHTM.Add("typestatus","Agendado");
StatusHTM.Add("exechourstatus", DateTime.Now.ToString("F"));
if (clsProc.ReprocessingDone)
StatusHTM.Add("statusstatus","OK");
else
StatusHTM.Add("statusstatus", "Falhou");
ClassStatus clsStt = new ClassStatus();
clsStt.StatusHT = StatusHTM;
clsStt.SaveStatus();
GetStatus();
}
}
}
catch (Exception ex)
{
ClassLog clsLog = new ClassLog();
clsLog.EventData = "Falha ao Iniciar a Execução do Aplicativo";
clsLog.ErrorLog();
clsLog.EventData = ex.ToString();
clsLog.ErrorLog();
}
}
I'm using the following code to open a text file and send emails to the people listed and changing the subject to include their ids. The issue i'm having is that the first time through testing I stopped the debugger on the subject line. The next thing I know I'm getting the test email. How could the code continue to execute even when I stopped the debugger?
Here is my code:
protected void btnTest_Click(object sender, EventArgs e)
{
string sFilePath = #"C:\email\" + ddlYear.SelectedItem.Value + "-" + ddlMonth.SelectedItem.Value + "_Num.txt";
using (TextFieldParser parser = new TextFieldParser(sFilePath))
{
parser.TextFieldType = FieldType.FixedWidth;
parser.SetFieldWidths(4, -1);
int iRowCnt = 1;
while (!parser.EndOfData)
{
string[] sCurrRow = parser.ReadFields();
try
{
System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage("test#test.com", sCurrRow[1].ToString());
message.Subject = txtSubject.Text + " - ID #" + sCurrRow[0].ToString() ;
message.IsBodyHtml = Convert.ToBoolean(ddlFormat.SelectedValue);
message.Body = txtMsg.Text;
System.Net.Mail.SmtpClient mailClient = new System.Net.Mail.SmtpClient();
mailClient.Host = "testSMTP.test.com";
mailClient.Credentials = new System.Net.NetworkCredential("TestSMTP", "TESTING"); //Username and password changes
mailClient.Send(message);
this.InsEmailDB(iRowCnt, iRowCnt, sCurrRow[1].ToString());
iRowCnt++;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
}
Stopping the debugger doesn't terminate the program, it just stops "watching" it-- the program will still run to completion.
Debugging as it's name suggests, is to error free the application. It only show you how it is executing. Stopping debug doesn't mean stopping application. And I think receiving test mail isn't big issue.
I hope you can help me with this problem. When I click a Email button, it takes few seconds to process before sending successfully. I need to put process image on but how to implement with "while" loop for processing.
Here is code: i think i should implement with client.Send(msg); for processing. How does it work? I will appreciate your example code. Thanks! (I am using C# and WPF)
private void BtnSendEmailClick(object sender, RoutedEventArgs e)
{
SmtpClient client = null;
MailMessage msg = null;
try
{
msg = new MailMessage
{
From = new MailAddress("me#hotmail.com", "Me Hotmail")
};
msg.To.Add(txtEmailAddress.Text);
msg.Priority = MailPriority.High;
msg.Subject = "Blah blah";
msg.Body =
"<!DOCTYPE html><html lang='en' xmlns='http://www.w3.org/1999/xhtml'>" +
"<head> </head>" +
"<body>" +
"<h3>Message</h3>" +
"<p>" + lblEmailMessage.Content + "</p>" +
"</body>" +
"</html>";
msg.IsBodyHtml = true;
client = new SmtpClient
{
Host = "smtp.live.com",
Port = 25,
EnableSsl = true,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("me#hotmail.com", "password"),
DeliveryMethod = SmtpDeliveryMethod.Network
};
//how to implement while loop for processing
client.Send(msg);
lblMessage.Content = "Successfully sent to your Mail!";
}
catch (Exception ex)
{
lblMessage.Content = ex.Message;
}
}
You will need to return instantly, and use a BackgroundWorker to send the email. Once it is finished, you can use the Dispatcher to notify the GUI. See http://msdn.microsoft.com/en-us/magazine/cc163328.aspx for more details.
See also How to use WPF Background Worker.
Are you wanting to display an image to indicate that the program is doing something (progress indicator)?
In that case you need to do the work of sending the email on a separate thread. You can do this in several ways. The easiest (if you are using .NET 4) is to use the await and async keywords. Simply display the image before starting your work. You'll need to extract the code that actually sends the email into a new method also. Like this:
private void BtnSendEmailClick(object sender, RoutedEventArgs e)
{
// Display progress image
progressImage.Visibility = System.Windows.Visibility.Visible;
string errorMessage = await SendEmail();
if (errorMessage == null)
{
lblMessage.Content = "Successfully sent to your Mail!";
}
else
{
lblMessage.Content = errorMessage;
}
progressImage.Visibility = System.Windows.Visibility.Hidden;
}
private async Task<string> SendEmail()
{
try
{
var msg = new MailMessage
{
From = new MailAddress("me#hotmail.com", "Me Hotmail")
};
msg.To.Add(txtEmailAddress.Text);
msg.Priority = MailPriority.High;
msg.Subject = "Blah blah";
msg.Body =
"<!DOCTYPE html><html lang='en' xmlns='http://www.w3.org/1999/xhtml'>" +
"<head> </head>" +
"<body>" +
"<h3>Message</h3>" +
"<p>" + lblEmailMessage.Content + "</p>" +
"</body>" +
"</html>";
msg.IsBodyHtml = true;
var client = new SmtpClient
{
Host = "smtp.live.com",
Port = 25,
EnableSsl = true,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("me#hotmail.com", "password"),
DeliveryMethod = SmtpDeliveryMethod.Network
};
//how to implement while loop for processing
client.Send(msg);
return "Successfully sent to your Mail!";
}
catch (Exception ex)
{
return ex.Message;
}
}
One final note: Be sure that you don't touch any UI components in your 'async' method as there is no guarantee that the code will be running on the UI thread. If you need more information returned from the async method you'll have to create a custom structure to contain the result and return it from that SendEmail() method.
Yesterday, i had a task assigned by my senior to build a windows forms application in .net which looked like the image i attached. I did all the stuff regarding the sending process of the email application, but i stuck at one place, i couldn't figure out how to authenticate the password in the email form. The password must be of the same email, which was provided in the "From :" fields.
Here is the code behind of my form,
public partial class Form1 : Form
{
MailMessage message;
SmtpClient smtp;
public Form1()
{
InitializeComponent();
lbl_Error.Visible = false;
}
private void chk_Show_Password_CheckedChanged(object sender, EventArgs e)
{
if (chk_Show_Password.Checked == true)
txt_Password.PasswordChar= '\0';
else
txt_Password.PasswordChar='*';
}
private void btn_Send_Click(object sender, EventArgs e)
{
btn_Send.Enabled = false;
txt_Password.Text = "";
try
{
message = new MailMessage();
if(isValidEmail(txt_From.Text))
{
message.From = new MailAddress(txt_From.Text);
}
if (isValidEmail(txt_To.Text))
{
message.To.Add(txt_To.Text);
}
message.Body = txt_Details.Text;
//attributes for smtp
smtp = new SmtpClient("smtp.gmail.com");
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new NetworkCredential("imad.majid90#gmail.com", "mypassword");
smtp.Send(message);
}
catch(Exception ex)
{
btn_Send.Enabled = true;
MessageBox.Show(ex.Message);
}
}
public bool isValidEmail(string email)
{
bool flagFalse = false; ;
if (!email.Contains('#'))
{
lbl_Error.Visible = true;
lbl_Error.ForeColor = System.Drawing.Color.Red;
lbl_Error.Text = "Email address must contain #";
return flagFalse;
}
return true;
}
}
Assuming you're using Gmail like the screenshot you posted shows, you can't check the password without trying to send the email.
My advice would be to attempt to send the email and catch an Exception if it fails. You can then show some indication that there has been an error, like a MessageBox or a Label on your form.
See the documentation for SmtpClient. The Send methods will throw an SmtpException if authentication fails.
EDIT:
Well, after seeing the additional code you posted, you are already handling any exceptions that are thrown, including an authentication failure. The user will see a MessageBox if the password is incorrect.
catch(Exception ex)
{
btn_Send.Enabled = true;
// MessageBox.Show(ex.Message);
lbl_Error.Text = "Invalid Username/Password";
}
Do a try catch for SmtpException and display the information to the user is unauthenticated.
http://msdn.microsoft.com/en-us/library/h1s04he7.aspx
It looks like your using Windows Authentication. It might be easier to fetch the user's email from Active Directory rather then prompting for credentials.
How to obtain email address with window authentication