We have an ASP.NET MVC application that sends a number of reports via e-mail to clients each month. Each e-mail attaches a monthly statement. Currently we have around 70 clients but this will hopefully increase over time. We have been seeing issues that a number of e-mails are not getting sent. We use the System.Net.Mail API.
Here is the code we are using, is there a better approach?
foreach(string client in clients){
SmtpClient client = new SmtpClient("server.com");
BackgroundWorker emailInvoker = new BackgroundWorker();
emailInvoker.DoWork += delegate
{
// Delay to prevent flow control, try later Relay error
Thread.Sleep(TimeSpan.FromSeconds(2));
client.Send(message);
}
emailInvoker.RunWorkerAsync();
}
We have been seeing issues that a number of e-mails are not getting
sent.
The larger (and more likely) problem than some of them aren't getting sent is that many of them are not getting delivered.
...is there a better approach?
In most cases. Jeff Atwood goes over many of the problems with sending email in this blog post. That post was almost 3 years ago and even then, the first comment recommends using postmark. I've used postmark and it reliably handles the problem of getting your emails out through code at a good price. That said, there are better solutions on the market now, the one my company is currently very tempted to switch to is mandrill. Slightly better pricing, awesome analytics.
Because this is an ASP.NET MVC application, you need to be aware of your application pool. Creating multiple threads will exhaust your app pool quickly, and IIS maybe doing some funky things to keep things from literally grinding to a halt while emails are being sent. I would take a look at Can I use threads to carry out long-running jobs on IIS? if you're interested on learning more.
If I were to rewrite that, I would create one thread with the foreach and email sending, instead of a thread for each customer.
BackgroundWorker emailInvoker = new BackgroundWorker();
emailInvoker.DoWork += delegate
{
// get your clients here somehow
foreach(string client in clients){
SmtpClient client = new SmtpClient("server.com");
// Delay to prevent flow control, try later Relay error
Thread.Sleep(TimeSpan.FromSeconds(2));
client.Send(message);
}
}
emailInvoker.RunWorkerAsync();
Related
We recently had an outage where one of our APIs became unresponsive due to our rabbit cluster being given artificially high load. We where running out of threads in mono (.NET) and requests to the API failed. Although this is unlikely to happen again we would like to put some protection in against this. Ideally we would have calls to bus.Publish() timeout after a set amount of time but we can't workout how.
We then came across the blocked connections notification feature of RabbitMQ and thought this might help. However we can't figure out how to get at the connection object that is in the IServiceBus. So far we have tried
_serviceBus = serviceBus;
var connection =
((MassTransit.Transports.RabbitMq.RabbitMqEndpointAddress) _serviceBus.Endpoint.Address)
.ConnectionFactory.CreateConnection();
connection.ConnectionBlocked += Connection_ConnectionBlocked;
connection.ConnectionUnblocked += Connection_ConnectionUnblocked;
But when we do this we get a BrokerUnreachableException which I don't understand.
My questions are, is this the right approach to detect timeouts and fail (we have a backup mechanism to collect the data in the message and repost later) and if this is correct, how do we make it work?
I think you can manage this by combining System.Timer or Observable.Timer to schedule checks, and the check, which use request-response. Consumer for the request should be inside the same process. You can specify a cancellation token with reasonable timeout for the Request call and it you get a timeout - your messaging infrastructure is down or too busy, or your endpoint is too busy.
I am trying to find a way to run a piece of code (MS Bot Framework, C# hosted on Azure) every time a person is mentioned on Yammer or receives a direct message.
The two ways that I tried:
1) The best I came up with for now is to enable email notifications from Yammer, and watch a mailbox for emails from notifications#yammer.com. Microsoft's Bot Framework has a one-click setup for monitoring emails, so that works.
But notification emails arrive with a 15 minutes delay, which renders this pretty useless as I need near-instant performance.
Finally, it looks like this approach simply doesn't work because the MS Bot Framework seems to reply to the email address who sent the email, rather to the one that I specify:
if (activity.ChannelId == "email" && activity.From.Id == "notifications#yammer.com")
{
var newActivity = activity.CreateReply();
//doesn't work, sends email back to the activity.From.Id
newActivity.Recipient.Id = "k48#gmail.com";
newActivity.Text = "I got a message from " + activity.From.Name + "!";
BotUtils.SendActivityToChat(newActivity);
}
I could write my own code for sending emails to an arbitrary recipient, but then there is still the problem with 15 min delay.
2) Another approach I am using is to poll Yammer's API every minute to see if there are new messages, but this is still not instant, and I'm not sure if my account gets banned if I keep polling the API way too often. (Update: the official rate limit is 1 poll per minute, or else they ban you).
Is there something I missed? How else would you run a piece of code every time you get a message or mention on Yammer?
The BotFramework will not allow you to reply to a message to a different address than the sender. However, if the recipient is one that the bot has received a message from before, you can send them a Proactive Message. To send a proactive message, you can keep the ServiceUrl and the user’s ChannelAccount (extracted from one of the messages from that user) and use this data to send a new activity from your bot to that user.
Here is an example in C#
Here is an example in Node.js
I am using multithreaded server to handle client communication, I don't know how many clients can this server handle. If number of clients increase will it be able to handle them? I am using it on core2duo processor.
Will starting server on different port solve the problem, if i redirect half of the clients to new server with another port?
Here is my code for server
Public void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
try
{
TcpClient client = this.tcpListener.AcceptTcpClient();
NetworkStream clientStream = client.GetStream(); //create networkstream for connected client
Console.WriteLine(((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());//client ipaddress
Console.WriteLine("connecting..");
Thread clientThread = new Thread(new ParameterizedThreadStart(updatedb));
clientThread.Start(client);
}
catch (Exception ex)
{
Console.WriteLine("exception" + ex.ToString());
Console.ReadLine();
}
}
}
I suggest you read this blog post and similar posts by the author. He explains there in great detail how multi threading is used by IIS / ASP.NET.
What you must remember, is that even if You can create more threads (by running anothre instance of your application, as you suggested, for example), it doesnt mean your application will be more responsive / return the expected answers to the clients faster, as there can be only as much running threads at any given moment as the number of CPUS your server has.
I dont think you need to write your code in an expectation of collapsing, but to work in a direction of more of an async processing, as the ISS server (which is practically doing the same - servicing TCP connections) is doing. Theres no reason not to use the thread pool provided by .NET, let it handle the real number of co-existing threads at every given moment, and let the other requests queue untill a thread becomes availibale.
Without actually trying it, everything else is a guess. As Hans Passant says, your strategy of creating a new thread for every request will not scale well. It may seem ok at first, but you should see performance fall off badly over a few hundred simultaneous users. In addition, it looks like the work will be communicating with a database (updatedb), so these threads you've created will just be sending data to an external process and waiting for a reply? That's the worst use of a thread. See if you can use asynchronous sql updates.
We are sending free newsletters to all users who have registered for this service. Since these newsletters are sent free of cost we expect at least 5000 subscribers within a month. I am worried whether bulk mailing using SMTP server concept will cause some issue. First we thought of developing a windows service which would automatically mail to subscribers on periodical basis but the business users have given requirement that the newsletters should be editable by the admin and then only mailed to users so we had to develop this functionality in website itself!. I get the subscribers for the particular user in data table and then mail to each user inside for loop, will this cause any performance issue?
The code is pasted below:
dsEmailds.Tables[0] has list of newsletter subscribers.
for (iCnt = 0; iCnt < dsEmailIds.Tables[0].Rows.Count; iCnt++)
{
MailMessage msg = new MailMessage();
msg.From = new MailAddress("newsletters#domainname.com", "test1");
msg.To.Add(dsEmailIds.Tables[0].Rows[iCnt]["mailid"]);
msg.IsBodyHtml = true;
msg.Subject = subject;
AlternateView av1 = AlternateView.CreateAlternateViewFromString(MailMsg, null, System.Net.Mime.MediaTypeNames.Text.Html);
av1.LinkedResources.Add(lnkResLogo);
av1.LinkedResources.Add(lnkResSalesProperty);
av1.LinkedResources.Add(lnkResLeaseProperty);
msg.AlternateViews.Add(av1);
SmtpClient objSMTPClient = new SmtpClient(System.Configuration.ConfigurationManager.AppSettings["mailserver"].ToString());
objSMTPClient.DeliveryMethod = SmtpDeliveryMethod.Network;
objSMTPClient.Send(msg);
}
Any suggestions would be great!
You should STOP and consider all sort of things:
Black List: with that amount you will for sure be balck listed in severeal ISP's / Mail Servers, and you need to prove that the received user asked for such email and wait 1 to 3 month process while they remove the flag
You need to send emails in blocks, not more than 250 at each time, use different IP's machines to send more emails (more blocks)
please read some nice guidelines for doing all this, you can find it in MailChimp and Campaign Monitor
Free Email Marketing Guides
You should use a service, like Mailchimp (now it's free to 1000 subscribes, 3000 sends a month) but prices are very cheap and they have an API that you can easily add, create, send and you will get all those nice reports on how opened, what did they do, etc ...
Campaign Monitor is fantastic as well, but a little bit more expensive but great as you can brand the entire UI and sell as a service to your customers (if you are thinking of doing such thing in the near future).
I hope it helps.
give them a try, I'm a happy customer.
The main problem i see is that you may encounter a page timeout. The best way to do it in my opinion would be to set up a service that will take care of mail-related uses (templating for example) by reading from a queue. Your website could just post the mails you expect to send in the queue, then offer a basic administration panel to manage the service and get some stats.
You can use open-source & xcopy-friendly systems for the queue like Rhino queue, or ServiceBus, and Topshelf for services if you want easy setup
But i'd recommend you not to send bulk emails in the webpage
There is a SendAsync method that will actually queue up these requests and send them async from your thread. This way you can prevent the timeout and you can probably send (ie. queue) 5000 emails within seconds.
Write to a pickup queue of an SMTP server running on the machine (IIS includes one). This is the fastest and most efficient method.
OR
Setup a custom thread pool in your code and offload the task to it. That way worker threads from ASP.NET thread pool are ready to serve incoming requests and won't be occupied with sending mails (that depends on how high your server load is, of course - go ahead with ASP.NET thread pool using async methods if you don't care about the load/can afford it).
This question already has answers here:
Email messages going to spam folder
(7 answers)
Closed 9 years ago.
I've got a C# application going that needs to send out an html email via smtp. The email gets sent just fine, but the default security setting on outlook (Low) classifies it as junk email.
It's not exactly a showstopper issue, but this is rather annoying, especially since the junk folder turns off html. I don't want to have to make everyone at my company do something special to receive these emails in a readable fashion, does anyone know what I could be doing that makes outlook think this is junk email?
Code that makes the email (basic stuff.) Config is an object that holds strings related to the configuration of this stuff, toList is a list of email addresses, body/subject are filled by other function calls.
Edit: To add, at the moment I'm just sending it out to myself. In the live version, we'll be looking at less than a hundred people being sent to in a worst-case.
Another Edit: It turned out to be happening much much more often for the longer emails I was generating the other day (~200-300 lines at the worst), and not the shorter emails I'm generating now. That's a reasonable enough filter criteria, I suppose.
SmtpClient smtp = new SmtpClient(config.SmtpServer);
NetworkCredential net = new NetworkCredential();
net.UserName = config.SmtpLogin;
net.Password = config.SmtpPass;
smtp.Credentials = net;
MailMessage msg = new MailMessage();
msg.IsBodyHtml = true;
msg.Priority = MailPriority.Normal;
msg.To.Add(String.Join(",", toList.ToArray()));
msg.From = new MailAddress(fromAddr, "Build Server");
msg.Body = "Blah html is here";
msg.Subject = "Build successful: #numberhere and stuff";
try
{
smtp.Send(msg);
}
catch (SmtpException)
{
//stuff
}
I think this is less of a programming issue and more of a configuration issue. The recipients need to add fromAddr to their “Safe Senders List”.
The thing is, if there were a way to configure an e-mail to bypass the junk mail filter then all the spammers will be doing it.
If it's a matter of crafting the perfect non-junk-looking e-mail then it may work sometimes and not others. And all the spammers will be doing it.
You're going to have to tell everyone to allow e-mails from that account. And you probably shouldn't start that e-mail with any unnecessary anatomical or medicinal references.
If your message To contains a large list it may be seen as spam. Try sending a unique email to each person instead of a mass email.
However:
If you're going to loop through your list and send an email for each user, you might want to consider creating a queue that will be processed that allows for failure and retry.
We had a similar issue in our system where after about 20,00 messages sent in quick succession (ie: within a foreach loop) the outgoing mail server rejected any further attempt to relay.
We instead added outgoing messages to a database table, and wrote a service that would process a specified number of emails at a time and then pause for a specified time before going again.
In addition this allowed us to capture failures, and then setup retry rules. After X attempts we mark the message as failed for good and report the issue. We found that this provided a much more reliable system of users getting their messages, plus they were no longer marked as spam.
If you are sending out several mails at a time send them in small batches so you're not flooding the server.
Check the text of the email for words and symbols likely to be considered spam by some filters.
You might also want to look into things such as SPF to reduce the chance that your mails will be marked as spam.
Add following line in your code while creating MailMessage
msg.BodyEncoding = System.Text.Encoding.GetEncoding("utf-8");
Just a thought, try looping through your to list and send a separate email. Also, try experimenting with different wording and html structures.