Send email using SendMailAsync from Nunit - c#

I'm trying to understand why I am not being able to send async mails (maybe it is related that I'm running it from NUnit?
When I do simple smtp.Send(mail);is it working well
// Nunit test
{
[TestFixture]
public class Tester
{
[Test]
public void TestSendTestMail()
{
// Arrange
// Act
await EbayProxy.Instance.SendTestMail();
// Assert
}
}
public async Task SendTestMail()
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress(_mailFrom);
mail.To.Add(_mailTo);
mail.Subject = "Test Mail Subject Async";
mail.Body = "Test Mail Body";
mail.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient(_smtpClient, Convert.ToInt32(_smtpPort));
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential(_mailFrom, _mailFromPassword);
await smtp.SendMailAsync(mail); // Not sending mail :(
}

Actually before you learn about Async/Await (which is a great topic!), I would question what it is that you are trying to achieve, full stop.
Why would you want to test the email facility itself, you should give the email client some element of trust but furthermore as mail isn't guaranteed you can only hope that the mail arrives at is destination. Actual acknowledgement would involve the recipient.
The email client seems to be a singleton but could potentially be passed in as a collaborator to another orchestrating class and you could use a mock and verify that the send mail method is called, trusting that the mail client does what it supposed to. I'm pretty certain that the mailing facility is part of some other process....
Furthermore, I'd use an integration type test for this external type command, to verify that when everything is plumbed in properly an actual email gets sent. But I suppose It could be argued what you have already is an integration test, and maybe that's your intention.

As explained many times before...
How to call asynchronous method from synchronous method in C#?
Calling async method synchronously
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
I think you'll find this code is causing a dead lock. Try...
[TestFixture]
public class Tester
{
[Test]
public async Task TestSendTestMail()
{
// Arrange
// Act
await EbayProxy.Instance.SendTestMail();
// Assert
}
}
public async Task SendTestMail()
{
MailMessage mail = new MailMessage();
mail.From = new MailAddress(_mailFrom);
mail.To.Add(_mailTo);
mail.Subject = "Test Mail Subject Async";
mail.Body = "Test Mail Body";
mail.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient(_smtpClient, Convert.ToInt32(_smtpPort));
smtp.EnableSsl = true;
smtp.Credentials = new NetworkCredential(_mailFrom, _mailFromPassword);
await smtp.SendMailAsync(mail); // Not sending mail :(
}
As discussed here...
How do I test an async method with NUnit, eventually with another framework?

Related

Wrong email titles when sending mails multiple times

First of all, my apologies if this is a duplicate question. I have searched for it a lot, but couldn't find related issues.
So here's the problem: I am using SmtpClient and MailMessage class to send mails. I am passing the subject of the mail as a parameter in the mail sending method. First time the mail is sent with the proper subject (the one i sent as parameter). However, in all next emails, no matter what subject i put, the subject remains the same (the one used first time). The subject is set from inside of the method.
(Note: This is a WindowsForm application)
What i have tried is, creating another method named "Refresh()" which disposes the mail object and creates it again (with from and to info only). And call this method each time after a mail is sent. But it doesn't help with this problem.
Codes are given below:
Fields:
MailMessage message;
SmtpClient mailer;
string from = "sender email";
string pass = "sender pass";
string to = "rec email";
Constructor:
try
{
message = new MailMessage(from, to);
mailer = new SmtpClient("smtp.gmail.com", 587);
mailer.Credentials = new NetworkCredential(from, pass);
mailer.EnableSsl = true;
}
catch(Exception ex) { /*code to write log*/ }
Refresh method:
void RefreshMessage()
{
try
{
message.Subject = "";
message.Dispose();
message = new MailMessage(from, to);
}
catch(Exception ex) { /*write log*/ }
}
Method which is sending the mail:
internal void TextOnly(string sub, string bodyMessage)
{
try
{
message.Subject = sub;
message.Body = bodyMessage;
mailer.Send(message);
this.RefreshMessage();
}
catch (Exception ex) { /*write log*/ }
}
Example of how it's called:
m.TextOnly("Subject 1" , SomeStringMethod());
m.TextOnly("Another Title " + anyString, "Some string mail");
m.TextOnly("[TAG] Email subject goes here" , AnotherStringMethod());
Now no matter whatever subject is sent in the parameter, it will always send with subject "Subject 1" (from the example above). The body of the message is fine, only the subject is not right.
I have few other methods in the class (for other purposes like sending mails with attachments for example), where subject isn't passed as parameter but it's set directly from within the method (like message.Subject = "Example Sub" from within the method), in that case it works fine.
But in the case above, where the subject is passed to the method, the subject remains the same.
Like the comment section already stated, there is no reason to cache the message itself. Currently, you're disposing the message(which actually puts it in a unusable state) and then you recreate it. Check out more HERE. You can just as well simply create new objects and dispose of them after you're done so the Garbage Collector can release the resources as soon as possible.
Just utilize a simple method for constructing MailMessages and send them directly.
internal MailMessage ConstructTextMailMessage(MailAddress from, MailAddress to, string subject, string body)
{
return ConstructTextMailMessage(from.Address, to.Address, subject, body);
}
internal MailMessage ConstructTextMailMessage(string from, string to, string subject, string body)
{
return new MailMessage(from, to, subject, body);
}
And then:
var mailClient = new SmtpClient("smtp.gmail.com", 587);
mailClient.Credentials = new NetworkCredential(from, pass);
mailClient.EnableSsl = true;
mailClient.Send(ConstructTextMailMessage(from, to, "Subject 1", SomeStringMethod()));
mailClient.Send(ConstructTextMailMessage(from, to, "Another Title " + anyString, "Some string mail");
mailClient.Send(ConstructTextMailMessage(from, to, "[TAG] Email subject goes here", AnotherStringMethod());
If you have attachments in the MailMessage, you should call Dispose after using them to clear up the streams. Also, call Dispose on the SmtpClient when you're done using it.
I used the same functionality (SntpClient, MailMessage etc.) in one of my programms and it worked just fine:
SmtpClient client = new SmtpClient("host", port);
MailMessage mail;
MailAddress absender = new MailAddress("mail#adress.from");
foreach (string sub in Subjects)
{
mail = new MailMessage();
mail.IsBodyHtml = true;
mail.Subject = sub;
mail.From = absender;
mail.To.Add("mail#adress.to");
client.Send(mail);
}
Mybe you just need to make a new MailMessage-Object each time you "create" a E-Mail.

Failed to send an EMail with body contains ip address and port no

I have create function to send an email. This function was work successful on localhost but on server its failed without any exception. I know the problem comes from my Port on IP Address.
The sample body is string body = "<p>Please click here</p>Thank You."
The problem is : between IP Address and Port.
Successful send an email if i remove :.
Do you guys have any ideas?
public void Sent(string sender, string receiver, string subject, string body)
{
using (MailMessage mail = new MailMessage(sender, receiver))
{
using (SmtpClient client = new SmtpClient())
{
client.Port = 25;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.Host = "mail.companyName.com.my";
mail.Subject = subject;
mail.IsBodyHtml = true;
mail.Body = body;
client.Send(mail);
}
}
}
You are doing it right, the code to send the mail is ok (you may want to revise the function name and make the smtp host name configurable, but that is not the point here).
The e-mail delivery fails on a relay, there is no immedieate feedback (no exception) to the client about this kind of failure.
The best bet is the IncreaseScoreWithRedirectToOtherPort property set in Set-HostedContentFilterPolicy in case your mail provider is Office365, or a similar spam filter mechanism in any other mail provider that is encountered down the mail delivery chain.
You can set a reply-to address and hope that the destination server will bounce a delivery failure that gives you more information. Or have the admin of the mail server look up the logs. More information here:
https://serverfault.com/questions/659861/office-365-exchange-online-any-way-to-block-false-url-spam
Try setting the 'mail.Body' to receive a Raw Html message instead of a encoded string, like:
mail.Body = new System.Web.Mvc.HtmlHelper(new System.Web.Mvc.ViewContext(), new System.Web.Mvc.ViewPage()).Raw(body).ToString();
Or put a using System.Web.Mvc at the beginning so it gets shorter and easier to understand:
using System.Web.Mvc
mail.Body = new HtmlHelper(new ViewContext(), new ViewPage()).Raw(body).ToString();

How to send Newsletters (bulk emails) asynchronously in ASP.NET

I need to send about 5000 emails as newsletter to my website users asynchronously.. The problem is i don't know the best way to send them asynchronously ..Please help me updating my code to make it asynchronously
My Code:
public string SendEmail()
{
foreach (var emailAddress in EmailList)
{
var message = new MailMessage("myemail#gmail.com", emailAddress);
message.Subject = "hi";
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.Credentials = new NetworkCredential("myemail#gmail.com", "*****");
client.EnableSsl = true;
client.Send(message);
}
return "done";
}
Thank you , Lucy
Take a look at the async and await keywords.
https://msdn.microsoft.com/en-us/library/mt674882.aspx
The async and await keywords in C# are the heart of async programming. By using those two keywords, you can use resources in the .NET Framework or the Windows Runtime to create an asynchronous method almost as easily as you create a synchronous method. Asynchronous methods that you define by using async and await are referred to as async methods.
MSDN explains the syntax side of things. The bigger concern is error handling and reliably. Dumping 5,000 emails into a list and hitting the "send" button on them is a little optimistic. Do these emails need to be reliably delivered? What happens if 3,000 of them send, and a network error suddenly causes temporary connectivity loss to the outgoing mail server? Are you going to resend all 5,000 when it starts working again? Just forget about the last 2,000? Are the recipients going to be mad because they got duplicates, or didn't get the message at all? How are you going to troubleshoot errors?
A pattern that I've found that has worked really well (whether you are sending synchronously or asynchronously), is to generate the messages and store each in a database table, and then use something like the following:
public void SendAllEmails()
{
var emails = SomeClass.GetAllUnsentEmails();
foreach(Email message in Emails)
{
var success = SendEmail(message);
if (!success)
{
// Do you want to do something if it fails?
}
}
}
public bool SendEmail(Email message)
{
try
{
// 1. Send the email message
// 2. Update the "SentOn" date in the database
// 3. return true
}
catch(Exception ex)
{
SomeClass.CreateEmailErrorEntry(message, ex); // store error in a table or log
return false;
}
}
edit: if it's being used inside of action you should mark your action async
public async Task<ActionResult> MyAction()
for a start, don't create SmtpClient for every message so as follows
and also this, should send the mails asynchronously but wait for all of them to be sent
public string SendEmail()
{
var tasks = new List<Task>();
var client = new SmtpClient("smtp.gmail.com", 587);
client.Credentials = new NetworkCredential("myemail#gmail.com", "*****");
client.EnableSsl = true;
foreach (var emailAddress in EmailList)
{
var message = new MailMessage("myemail#gmail.com", emailAddress);
message.Subject = "hi";
tasks.Add(client.SendMailAsync(message));
}
while(tasks.Count > 0)
{
var idx = Task.WaitAny(tasks.ToArray());
tasks.RemoveAt(idx);
}
return "done";
}

Unit Test for SendAsync Mail

Today I am trying to create a unit test in visual studio for sending a email i am struggling with finding the best way to do it and using SendCompleted event as a validation for message been actually send.
Here i code i apply to send email but after using many different ways i just paste here clean code and maybe you can tell me what i am doing wrong or give me better way to solve it.
Here is my code what i have tried so far :
[TestClass]
public class sendEmailTest
{
[TestMethod]
public void sendAsyncEmailTest()
{
string from = "sender#test.com";
string to = "receiver#test.com";
MailMessage mail = new MailMessage(from, to);
mail.Subject = "Unit Test MVC";
mail.Body = "Unit Test for sending mail in MVC app";
mail.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.test.com";
smtp.EnableSsl = true;
NetworkCredential networkCredential = new NetworkCredential(from, "testpassword");
smtp.UseDefaultCredentials = true;
smtp.Credentials = networkCredential;
smtp.Port = 587;
smtp.SendAsync(mail, null);
smtp.SendCompleted += new SendCompletedEventHandler(smtp_SendCompleted);
}
static void smtp_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
}
}
What you probably need is dummy dev SMTP server.
You can get it from here
Once it's running on your dev machine you can send emails setting smtp.Host to 'localhost' and using dummy email addresses.
However as mentioned in comments such unit test isn't useful at all as whether email is sent successful or not depends on many external factors like e.g network connection. If you past test on your local machine it does not mean sending email going to be successful every time on production server.

How do I avoid a delay when sending email from my application?

I have a small console application. It checks a few settings, makes some decisions, and sends an email. The problem is the email doesn't actually get sent until my application finishes. I want the email sent as soon as my method that sends the email completes.
Initially, I just created a MailMessage and called .Send(). That's when I noticed the mail was not being sent until the app finished.
Then I tried using the task parallel library.
var taskA = Task.Factory.StartNew(() => msg.Send());
Again, the messages don't get sent until my entire application finishes.
How do I sent an email when msg.send executes, not when the app completes?
SmptClient supports async sending of mail via SendAsync, however in practice in a web application this hangs the request thread.
To avoid blocking I recommend using the ThreadPool to fire off the email in a background thread. This won't block your application.
ThreadPool.QueueUserWorkItem(o => {
using (SmtpClient client = new SmtpClient(...))
{
using (MailMessage mailMessage = new MailMessage(...))
{
client.Send(mailMessage, Tuple.Create(client, mailMessage));
}
}
});
The most sure fire way to avoid delays would probably be to use a pickup directory, which will queue the message rather than send it immediately.
you should use a SMTP client. do it like this:
MailMessage mm = new MailMessage();
//fill in your message
NetworkCredential nc = new NetworkCredential(FromAddress, FromPassword);
SmtpClient sc = new SmtpClient(SmtpHost, SmtpPort);
sc.EnableSsl = true;
sc.Credentials = nc;
sc.Send(mm);
at this stage your mail will be sent.
But, sending an email is an async act, so it will take some time until you recive the mail.
Create a new MailMessage and send it with SmtpClient. It will send immediately. I will add an example.
EDIT: Populate the variables host, port with the smtp ser ver name and port number.
using (var mailer = new SmtpClient(host, port))
{
using (var message = new MailMessage(sender, recipient, subject, body) { IsBodyHtml = false })
{
mailer.UseDefaultCredentials = false;
mailer.Credentials = new NetworkCredential(user, pass);
mailer.EnableSsl = useSSL;
mailer.Timeout = Timeout;
mailer.Send(message);
}
}
If you still experience a delay, then the delay will be at the mail server.
Simply dispose the MailMessage and SmtpClient objects after the .Send() function.
SmtpClient smtpClient = new SmtpClient("server", 25);
smtpClient.UseDefaultCredentials = true;
MailMessage message = new MailMessage("ToAddress","FromAddress");
message.Subject = "Test email";
message.Body = "Test email";
smtpClient.Send(message);
message.Dispose();
smtpClient.Dispose();
Use SmtpClient with setting:
smtpClient.ServicePoint.MaxIdleTime = 2;
https://weblogs.asp.net/stanleygu/tip-14-solve-smtpclient-issues-of-delayed-email-and-high-cpu-usage

Categories

Resources