I'm having some wierd behaviour in my WinForm application coded in c#.
in my:
private void buttonSave_Click(object sender, EventArgs e)
Im calling my function:
functions.sendStatusEmail();
The weird thing is that, when I press the Save button then email send is not triggered. But if I close my application the mail is handle and sent.
Have I missed something or do one need to trigger som application event manually to have run the sendout.
( I tried using client.SendAsync(mail,null); then it triggerd at click but the mail was empty)
Thanks in advance
--
Edit: code expamples
private void buttonSave_Click(object sender, EventArgs e)
{
// checks if a ticket is active
if (workingTicketId > 0)
{
// update ticket information
functions.updateTicketInfo(workingTicketId, comboBoxPriority.SelectedIndex,
comboBoxStatus.SelectedIndex, textBoxComment.Text);
// gives feedback
labelFeedback.Text = "Updated";
// updates the active ticket list
populateActiveTicketList();
// marks working ticket row in list
dataGridActiveTicketList.Rows[workingGridIndex].Selected = true;
// checks for change of ticket status
if (comboBoxStatus.SelectedIndex != workingTicketStatus)
{
// checks if contact person exists
if (labelContactPersonValue.Text.ToString() != "")
{
// sends email to contact person
functions.sendStatusEmail(labelContactPersonValue.Text, comboBoxStatus.SelectedIndex, workingTicketId, textBoxDescription.Text);
}
// updates working ticket status
workingTicketStatus = comboBoxStatus.SelectedIndex;
}
}
}
and the send email function:
// sends a status email to contact person
// returns noting
public void sendStatusEmail(string email, int newStatus, int ticketId, string ticketText)
{
// defines variables
string emailSubject;
string emailBody;
// some exkluded mailcontent handling
// sends mail
MailMessage mail = new MailMessage("myFromEmail#hidden.com",email,emailSubject,emailBody);
SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["MailSMTP"]);
mail.IsBodyHtml = true;
client.Send(mail);
// dispose
mail.Dispose();
}
Cannot understand why it would not work. I used below function and it sends the email successfully:
public static bool SendEmail (string smtpServer, string fromAddress, string fromDisplayName,
string toAddress, string subject, string contents, bool important) {
MailAddress from = new MailAddress (fromAddress, fromDisplayName);
MailPriority priority = important ? MailPriority.High : MailPriority.Normal;
MailMessage m = new MailMessage {
From = from,
Subject = subject,
Body = contents,
Priority = priority,
IsBodyHtml = false
};
MailAddress to = new MailAddress (toAddress);
m.To.Add (to);
SmtpClient c = new SmtpClient (smtpServer) { UseDefaultCredentials = false };
c.Send (m);
return true;
}
No offence but are you sure that it is closing the application which results in email being sent. Most of the times there is a delay between an email is sent and it is received because of the traffic on SMTP server. Try pressing that button and then wait for some time (3-4 minutes) and try refreshing your inbox during that time.
BTW, the SendAsync didnt work because you called mail.dispose() after the Async call.
The right way to do it in async would be,
private void button1_Click(object sender, EventArgs e)
{
MailMessage mail = new MailMessage("from#domain.com", "to#domain.com", "subj", "body");
SmtpClient client = new SmtpClient("SMTPHOST");
mail.IsBodyHtml = true;
client.SendCompleted += new
SendCompletedEventHandler(SendCompletedCallback);
client.SendAsync(mail,mail);//send the mail object itself as argument to callback
}
private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
//Mail sending is cancelled
}
if (e.Error != null)
{
//There is an error,e.Error will contain the exception
}
else
{
//Do any other success processing
}
((MailMessage)e.UserState).Dispose();//Dispose
}
Related
I am making a bulk mail sender which will take mail addresses from DB. All is okay, test mails are sending but the success message is showing only after all the mails are sent. I want a message box or a progress box to count the mails that are passing. Help me to add a message pomp to count the mails have been sending. Here the Code I am using for sending mails, please write me the code for the message box to show the count -
private void btnSendEmail_Click(object sender, EventArgs e){
string subject = txtSubject.Text;
string message = txtMessage.Text;
if (!txtFile.Text.Equals(String.Empty))
{
if (System.IO.Directory.GetFiles(txtFile.Text).Length > 0)
{
foreach (string file in System.IO.Directory.GetFiles(txtFile.Text))
{
}
}
else
{
}
}
var con = "Data Source=Ashiq-pc;Initial Catalog=OfferMails;Integrated Security=True;MultipleActiveResultSets=True";
List<EmailModel> emailList = new List<EmailModel>();
using (SqlConnection myConnection = new SqlConnection(con))
{
string oString = "Select * from tbl_MailAdd where Flag=#Flag";
SqlCommand oCmd = new SqlCommand(oString, myConnection);
oCmd.Parameters.AddWithValue("#Flag", true);
myConnection.Open();
using (SqlDataReader oReader = oCmd.ExecuteReader())
{
while (oReader.Read())
{
EmailModel emailModel = new EmailModel();
emailModel.ID = Convert.ToInt16(oReader["ID"]);
emailModel.EmailAdd = oReader["EmailAdd"].ToString();
emailModel.Flag = Convert.ToBoolean(oReader["Flag"]);
emailList.Add(emailModel);
}
myConnection.Close();
}
}
//return matchingPerson;
foreach (EmailModel email in emailList)
{
try
{
SmtpClient client = new SmtpClient("smtp.gmail.com");
client.Port = 587;
client.EnableSsl = true;
client.Timeout = 100000;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("my mail", "my pass");
MailMessage msg = new MailMessage();
msg.To.Add(email.EmailAdd);
msg.From = new MailAddress("my from name");
msg.Subject = subject;
msg.Body = message;
if (!txtFile.Text.Equals(String.Empty))
{
if (System.IO.Directory.GetFiles(txtFile.Text).Length > 0)
{
foreach (string file in System.IO.Directory.GetFiles(txtFile.Text))
{
//Add file in ListBox.
listAttch.Items.Add(file);
//System.Windows.Forms.MessageBox.Show("Files found: " + file, "Message");
Attachment data = new Attachment(file);
msg.Attachments.Add(data);
}
}
else
{
//listBox1.Items.Add(String.Format(“No files Found at location : {0}”, textBox1.Text));
}
}
//Attachment data = new Attachment(textBox_Attachment.Text);
//msg.Attachments.Add(data);
client.Send(msg);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//for (int i = 0; i < emailList.Count; i++)
//{
// MessageBox.Show("i++");
//}
MessageBox.Show("Successfully Sent Message.");
}
First, let me just say that asking for someone to write this code for you is a bit frowned upon here. But I know what you're asking so I'm willing to help out a bit.
Firstly, a message box by itself isn't going to work for this, because a message box ends up stopping the thread where it is until a the DialogResult event is handled. So, for that being said, you will probably want to build another form (I am assuming that you're doing this with Windows Forms here.) to do the progress for you. If you want it to be a counter, then you could do it using a label that is changing its text as each mail is sent.
So, with that being said, however, if you're doing this with a Windows Form, the issue you will run into is the form will never update until after your
foreach loop finishes. This is because of the way that C# handles thread usage.
For what you want to accomplish, you'll need to utilize the BackgroundWorker. This allows you to run cumbersome operations asynchronously.
Here is an example that you could use to get your system working:
//used to be a counter for your progress
int i_counter = 0;
//create a background worker instance
public BackgroundWorker bg_worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
//set this to true if you want to have an event where you can cancel the background task
bg_worker.WorkerSupportsCancellation = true;
//this is needed to actually show your progress, allows the background worker to report it is working
bg_worker.WorkerReportsProgress = true;
//assigns the "DoWork" and "ProgressChanged" Handlers to the background worker.
bg_worker.DoWork += new DoWorkEventHandler(bg_worker_DoWork);
bg_worker.ProgressChanged += new ProgressChangedEventHandler(bg_worker_ProgressChanged);
}
//Mail method
public void MailerMethod()
{
//all of the things you want to happen for your mailing methods
foreach(//your loop stuff in here)
{
//THIS NEEDS TO HAPPEN TO CAUSE THE COUNTER TO UPDATE
bg_worker.ReportProgress(i_counter);
}
}
//the stuff that you want done in the background
//fires when "RunAsync" is called by BackgroundWorker object.
private void bg_worker_DoWork(object sender, DoWorkEventArgs e)
{
//IN HERE IS WHERE YOU WANT YOUR EMAIL STUFF TO HAPPEN
bg_worker = sender as BackgroundWorker;
MailerMethod();//or just all of your mailing code, it looks nicer like this though
}
//fires when worker reports the progress has changed
//caused by "ReportProgress" method
private void bg_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lb_counter.Text = Convert.ToString(i_counter);
}
//this is what will happen when the worker is done.
//you can have it do a alot of things, such as write a report, show a window, etc.
private void bg_worker_RunWorkComplete(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("DONE!", "DING DING!");
Application.Exit();
}
//button click event to start this shindig
private void bt_start_Click(object sender, EventArgs e)
{
//makes sure the background worker isn't already trying to run
if (!bg_worker.IsBusy)
{
//calls the DoWork event
bg_worker.RunWorkerAsync();
bt_start.Visible = false;
}
}
May I direct you here for the official MDSN documentation.
And here for a basic tutorial on how to set up a BackgroundWorker.
Hope this helps, let me know how it goes.
Use a Progress bar with its Position property set to zero, Max property set to the number of emails you are sending and the Step property set to 1, unless you want to step every 10 or so emails then you would use % 10 in your loop to increase the progress. In your loop simply increase the position of the ProgresBar or call Step().
I have this simple code which works for me if i hardcode all the requirements i.e. send/receipent email address etc. but throws exception for if used in Form:
mail.From = new MailAddress(fromtext);
throws ArgumentException was unhandled
The parameter 'address' cannot be an empty string.
Parameter name: address
Complete Code:
private void Form1_Load(object sender, EventArgs e)
{
MailMessage mail = new MailMessage();
SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
string FromPass ="******" ;
string fromtext=FromText.Text;
string totext = ToText.Text;
string subject = SubjectText.Text;
string Message = MessageBody.Text;
mail.From = new MailAddress(fromtext); //exception
mail.To.Add(totext);
mail.Subject = subject;
mail.Body = Message;
/* if (fD.FileName != string.Empty)
{
Attachment attachment;
attachment = new Attachment(fD.FileName);
mail.Attachments.Add(attachment);
}*/
SmtpServer.Timeout = 10000;
SmtpServer.DeliveryMethod = SmtpDeliveryMethod.Network;
SmtpServer.Port = 587;
SmtpServer.Credentials = new NetworkCredential(fromtext, FromPass);
SmtpServer.EnableSsl = true;
SmtpServer.Send(mail);
}
Any Suggestions !!!!
I'm not sure why you have placed this code into your Form1_Load Event, as this does not allow the user to enter any data into the form.
What I think you mean to do, is have a submitButton onclick event where you can then check:
if (fromText.Text !="" && ToText.Text !="" &&...)
{
//call a method here to send message, including adding it to body/etc.
//you may want to do further validation checks here too!
}
else
{
MessageBox.Show("Please enter all details","Some credentials Missing");
}
In future, I think you may also benefit from inserting a breakpoint (press F9) to then step slowly through your code (line by line) to see where any errors occur. But in this example, you have just placed your code in the form1_load event (which executes when the form loads, and not after user input).
system.net.mail.smtpclient has two methods for which I am very confused.
1 . SendAsync(MailMessage, Object)
Sends the specified e-mail message to an SMTP server for delivery. This method does not block the calling thread and allows the caller to pass an object to the method that is invoked when the operation completes. -MSDN
2 . SendMailAsync(MailMessage)
Sends the specified message to an SMTP server for delivery as an asynchronous operation. -MSDN
Notice that the names of two methods are different so it is not an overload. What exactly is the difference here?
I am looking for very clear answer as the description given by MSDN for both methods is very ambiguous (at least for me it is.)
The difference is one SendMailAsync uses the new async/await technology and the other uses the old callback technology. And more importantly, the Object that's passed is simply passed into the event handler as the userState when the method completes.
Firstly, they both work asynchronously.
However, SendAsync has existed since .NET 2. In order to maintain backwards compatiblity whilst supporting the new Tasks system SendMailAsync was added.
SendMailAsync returns a Task rather than void and allows the SmtpClient to support the new async and await functionality if required.
//SendAsync
public class MailHelper
{
public void SendMail(string mailfrom, string mailto, string body, string subject)
{
MailMessage MyMail = new MailMessage();
MyMail.From = new MailAddress(mailfrom);
MyMail.To.Add(mailto);
MyMail.Subject = subject;
MyMail.IsBodyHtml = true;
MyMail.Body = body;
MyMail.Priority = MailPriority.Normal;
SmtpClient smtpMailObj = new SmtpClient();
/*Setting*/
object userState = MyMail;
smtpMailObj.SendCompleted += new SendCompletedEventHandler(SmtpClient_OnCompleted);
try
{
smtpMailObj.SendAsync(MyMail, userState);
}
catch (Exception ex) { /* exception handling code here */ }
}
public static void SmtpClient_OnCompleted(object sender, AsyncCompletedEventArgs e)
{
//Get the Original MailMessage object
MailMessage mail = (MailMessage)e.UserState;
//write out the subject
string subject = mail.Subject;
if (e.Cancelled)
{
Console.WriteLine("Send canceled for mail with subject [{0}].", subject);
}
if (e.Error != null)
{
Console.WriteLine("Error {1} occurred when sending mail [{0}] ", subject, e.Error.ToString());
}
else
{
Console.WriteLine("Message [{0}] sent.", subject);
}
}
//
}
//SendMailAsync
public class MailHelper
{
//
public async Task<bool> SendMailAsync(string mailfrom, string mailto, string body, string subject)
{
MailMessage MyMail = new MailMessage();
MyMail.From = new MailAddress(mailfrom);
MyMail.To.Add(mailto);
MyMail.Subject = subject;
MyMail.IsBodyHtml = true;
MyMail.Body = body;
MyMail.Priority = MailPriority.Normal;
using (SmtpClient smtpMailObj = new SmtpClient())
{
/*Setting*/
try
{
await smtpMailObj.SendMailAsync(MyMail);
return true;
}
catch (Exception ex) { /* exception handling code here */ return false; }
}
}
}
SendMailAsync a simple TAP wrapper for SendAsync
More info: Are the SmtpClient.SendMailAsync methods Thread Safe?
I had a web service to send email in C#
[WebMethod]
public string sendEmail()
{
MailMessage mail = new MailMessage();
SmtpClient smtpsvr = new SmtpClient("smtp.gmail.com");
// mail settings
// smtpsvr settings
smtpsvr.SendCompleted += new SendCompletedEventHandler(sentCompleteCallBack);
try
{
smtpsvr.SendAsync(mail, "Email 1");
return "sent"; //this return only indicate email has been sent out
}
catch (Exception)
{
return "failed";
}
}
private void sentCompleteCallBack(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null) //error
{
sendResult = "email failed " + (string)e.UserState;
}
else
{ //this result, indicate the process of sending email has been completed
sendResult = "email sent " + (string)e.UserState;
}
// ??? haw to pass sendResult value to client page
}
I tried using properties string, class string to get sendResult value; but at the end in client page (aspx), only got empty/null. I only can get string sendEmail() value.
How to pass back the sendResult value to client ?
Thanks so much for the help !
/**********/
edited
May be I have to change the code like this ? (still using sendAsync()
[WebMethod]
public string sendEmail()
{
MailMessage mail = new MailMessage();
SmtpClient smtpsvr = new SmtpClient("smtp.gmail.com");
//mail settings
//smtpsvr settings
smtpsvr.SendCompleted += new SendCompletedEventHandler(sentCompleteCallBack);
try
{
smtpsvr.SendAsync(mail, "email 1");
return "sent";
}
catch (Exception)
{
return "failed";
}
}
private void sentCompleteCallBack(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null) //error
{
//write to DB_email_status = "failed"
}
else
{
//write to DB_email_status = "success"
}
}
in client side page (aspx) :
(1) call web service to send email.
(2) get email sent string value from sendEmail() method.
(3) button_onclick : view/get data from DB_email_status.
(???) is this case achieveable ?
(!!!) Thanks so much.
If you are using stateless protocol as in HTTP , then the server(Web service) can give only one response to the client. So, there is no way for the WebService to send details of the Async results to the client unless the client probes it again for status.
IMO, your best bet is to use .Send() instead of .SendAsync(). You can use Timeout property to prevent the method from hanging.
Why dont you just pass in a bool as return value in your SendEmail method like below
bool sentEmail()
{
bool isValid = false;
try
{
//if email successful
isValid = true
}
catch(Exception ex)
{
//Email Fails
isValid = false;
}
return isValid;
}
or using send() and thread.
[WebMethod]
public bool sendEmail()
{
//mail settings
//smtp settings
try
{
smtp.Send(mail);
return true;
}
catch
{
return false;
}
client page (aspx)
private void send()
{
Thread.Sleep(100;
//call web service: sendEmail()
if true
{ label.Text = "sent"} else {label.Text = "fail"}
}
private void button_Onclick(...)
{
Thread t = new Thread (send);
t.Start();
t.Join();
}
will behave similiar like sendAsync(), but easier to get return value.
I use SendCompletedEventHandler of SmtpClient when sending a list of emails.
The SendCompletedEventHandler is only called when have already sent all emails in the list.
I expexted, that SendCompletedEventHandler is called when an email is sent.
Is there something wrong in my code?
public void SendAllNewsletters(List<string> recipients)
{
string mailText = "My Text";
foreach(string recipient in recipients)
{
//if this loop takes 10min then the first call to
//SendCompletedCallback is after 10min
SendNewsletter(mailText,recipient);
}
}
public bool SendNewsletter(string mailText , string emailaddress)
{
SmtpClient sc = new SmtpClient(_smtpServer, _smtpPort);
System.Net.NetworkCredential SMTPUserInfo = new System.Net.NetworkCredential(_smtpuser, _smtppassword);
sc.Credentials = SMTPUserInfo;
sc.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);
MailMessage mm = null;
mm = new MailMessage(_senderemail, emailaddress );
mm.IsBodyHtml = true;
mm.Priority = MailPriority.Normal;
mm.Subject = "Something";
mm.Body = mailText ;
mm.SubjectEncoding = Encoding.UTF8;
mm.BodyEncoding = Encoding.UTF8;
//Mail
string userState = emailaddress;
sc.SendAsync(mm, userState);
return true;
}
public void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
// Get the unique identifier for this asynchronous operation.
String token = (string)e.UserState;
if (e.Error != null)
{
_news.SetNewsletterEmailsisSent(e.UserState.ToString(), _newslettername, false, e.Error.Message);
}
else
{
_news.SetNewsletterEmailsisSent(e.UserState.ToString(), _newslettername, true, string.Empty);
}
}
You are creating a new instance of SmtpClient each and every time (and then re-assigning the handler). Use a static variable with a bigger scope.
It works as expected on my machine except that the constructor of MailMessage throw a format exception because "My Tex" is not a valid email address. The first argument is the email address of the sender.
As Josh Stodola points out, you should cache the SmtpClient for the life of this class rather than creating another one for each call. If you don't cache the SmtpClient, then you should add the following line to the end of your SendCompletedCallback (preferably in a finally block):
((SmtpClient)sender).SendCompleted -= SendCompletedCallback;
If this doesn't help you, perhaps you could post more details - such as what is the data in the event args that do get called?