How do you send mass emails from ASP.NET? - c#

I built a website for a client and they would like a custom newsletter tool. Building the tool was easy, but I'm not sure how to send the email.
I set up a test page and managed to send a test email to myself using the System.Net.Mail namespace. I tried applying this code to a loop on the newsletter page, but it's turning out to be quite a difficult task. The email sending loop locks up the whole site for about an hour while it sends its emails. Sometimes it will abort the loop midway and some of the emails won't get sent.
I tried starting the loop on another thread.
protected void btnSendNewsletter_Click(object sender, EventArgs e)
{
Thread t = new System.Threading.Thread(new ThreadStart(SendEmails));
t.Start();
}
but this still makes the site go slow and also has a habit of aborting part way through. What is the common method for sending mass emails? I'm sure I'm not doing it right.
I am very new to the email arena in .NET.

For this kind of task you're better to add a bunch of jobs to a queue. Then have a thread running which pulls x number of jobs from the queue, processes them (i.e. sends the emails) and then sleeps for a period of time. This will give you web app some breathing space.
If you're using a database you can create an Email Queue table to store the jobs. I prefer to use this kind of storage over memory incase the app recycles for some reason or an exception is thrown...atleast you can then pick up from where you left off.
Generally, the process running the worker thread wouldn't be the web app itself. It would be a windows service or something similar. This might not be possible if you're on shared hosting.

Related

How to wait 24hrs before completing an async task?

I'm making an MVC app with the .NET Framework and in one of my controllers I call an async task that sends an e-mail to the signed in user.
This task is called upon when the user clicks a specific checkbox and the e-mail is meant to work as sort of reminder.
The entire task works as intended (the user gets an e-mail when the checkbox is checked), but I need it to wait 24 hours before actually sending the e-mail, as it is a reminder.
Currently the e-mail is sent right away, how can I delay the completion of my "e-mail task", while the code continues?
Use a library like Hangfire which lets you schedule background jobs and backs them with persistent storage.
You can then easily schedule a job like:
BackgroundJob.Schedule(
() => SendEmail("user#domain"),
TimeSpan.FromDays(1));
This is a classic X Y Problem. While it may be possible to make your system wait 24 hours you are creating a very fragile system that can be affected by app pool resets and server reboots.
Putting aside the possibility of an unexpected reboot, what happens when your maintenance cycle comes around and a scheduled reboot is going to happen? How many queued email reminders will you have that you can't do anything with?
The best approach for systems that don't immediately use their data is to buffer it through some form of storage scheme. It could be as simple as writing queued emails to files on the system, or something more robust like a database with a dedicated email sending service.
I have used a LOT of email sending systems over the years, and even for immediate sends we have used a database intermediary, with one dedicated email sending Windows service to produce and send the actual email. By centralizing the email production you not only get one place to maintain your email sending code, but you can also increase the durability of the whole system.
Bonus points if your database is part of a high availability cluster, as in this kind of system the database becomes the critical point. If it is then you're protected from any form of downtime other than a total network outage.
Let the Task wait for 24 hours before sending the mail.
await Task.delay(TimeSpan.FromHours(24));
Add this line in your async function bfore sending the email

Solve a Timeout Error caused by slow email

The Problem
I have a web service that saves a record in the database and, sometimes send out notification emails to a group of users letting them know an event occurred.
I am getting infrequent time-out errors from the client. Since the data are committed to the database, I think my problem is that sending the SMTP server sending the emails is taking longer than the timeout on the client.
The Need
What I am need to do is to send the email either in the background or add it to some sort of queue for sending later and return.
Constraints
Our site runs .Net 2.0 and IIS 6
I do not have admin rights to the server, although I do have file-system access to our web site. While I may be able to convince our server admin to install a custom windows service for me, I would prefer to avoid this if possible.
Our web server is old and slow and is shared with several other web sites.
This problem occurred in an important online data entry system, where downtime and errors cause political issues.
Ideas
I've looked at several solutions, but need some direction as to which way would be best.
I could spawn a thread to send the emails, but I don't know if that
would work, since the web service code would fall out of scope upon
return.
I could add the task to some sort of queue, and periodically send queued emails.
increase the timeout on the client side and ignore the problem.
Under #2, I've looked at Jeff Atwood's use of the HttpRuntime.Cache to simulate a windows service but am very concerned with the warning
You need to really be careful on the length of the task running.
Every new Task is a new Worker Thread and there’s a limited number of
those – as it “borrows” a thread from the managed thread pool.
An unresponsive web page is worse than the error I'm trying to solve.
What direction should I go?
The Web Service Code
[WebMethod(CacheDuration = 0)]
public static string SaveRecord(comRecord record, IList<QIData> qiItems)
{
using (WebDatabase db = new WebDatabase())
{
db.SaveRecord(record, qiItems, UserId, ComId);
if (qiItems.Count>0)
{
/*Then somehow invoke or queue the routine
db.SendQINotice(record,UserId, (int)ComId));
*/
}
}
}
Interesting - there are several ways to do it, but since you are on a web site, I would add an entry to an e-mail queue in a database and have another task send out the e-mail. Then you have the freedom to do some better error handling on the e-mail send if you need to without slowing down the web site. For instance, you could add some "transient" error handling to such an application. If you are interested in this approach, I can add to my response the "transient" error handler that I am using to retry on an exception to overcome some temporary error conditions.

Background thread / process

I have a application that will allow a user to upload a file. After the upload is complete there are a number of processing steps that must be done on the server (decompression, storage, validation, etc ...) thus the user will be informed sometime later by email when everything is complete.
I have seen a number of examples where the BackGroundWorker from System.ComponentModel is used to allow asynchronous work to be done in another thread. However, it seems like they lead to the user eventually getting a response. In our case no web response is necessary - the code can take up to 30 minutes to complete.
Is there another way to start a completely separate thread/process that will keep running even after the user completely closes their session?
If there is no need to respond immediately, you want to offload to some other process to do the heavy lifting. I would dump it in a DB, folder or post to a Message Queue. The worker processes (Windows Services?) would process the files, reading from the db, file system or queue. When the work is done, your worker process can call out to your ASP app (webhook style) if it needs to know when it's done. Just a suggestion.
Write a Windows Service that will run on the ASP.NET server. Architect it in such a way that it can accept and queue job requests. The queue will allow you to create the optimal number of threads in a ThreadPool for executing a subset of the queued jobs concurrently. Submit jobs to the Windows Service using either .NET Remoting, or WCF.
If processing can take up to 30 minutes, I'd recommend skipping using a background thread from the the web worker process and using something like a Windows service instead, or running a console application on a schedule using the Windows scheduler.
Once the file is uploaded, you would add it to a queue of some sort (either in a database, or using a message queuing system like RabbitMQ if you're feeling adventurous). Your web request could then return immediately and let the user know that the file is being processed, and the background service would pick the item up off the queue and continue the processing, emailing the user when it is complete.

Should I use thread.sleep or timer in my code?

I have the following code which send out SMS to the subscribers. However, some SMS were rejected from the SMSGateway because I'm sending too many SMS at one time. So I'm thinking to make a delay in between.
Sending out the SMS like this -
foreach (DataRow row in dt.Rows)
{
//Gets Subscriber number
smsSender.destinationNum = Convert.ToInt64(row["callerID"]);
foreach (DataRow articleRow in dtArticle.Rows)
{
//Gets SMS content
smsSender.smsMessage = articleRow["news"].ToString();
//Then send out the SMS
smsSendder.sendSMS();
}
}
Please advice because I have no experience with the threads and timers
It would depend on the architecture of the application.
Assuming this is a service-style app, with no user interface, that simply gets data out of the database and sends it to SMS, then Thread.Sleep(...) is fine.
If this app has a user interface, and you're running this SMS sending code on the UI thread, then Thread.Sleep(...) will block your UI. Actually, smsSender.sendSMS is probably already blocking your UI in this case!
Refactoring so that this code is off the UI thread is the answer. And you can do that simply by using a timer, although you will have to refactor the code so that the result set is cached in a local object and the timer iterates through the set sending one SMS out at a time.
In either case, I hope you don't have a lock on the database while you're sending SMSes.
Your question is tagged [asp.net] so I assume that you have a webpage that when requested will send a number of SMS messages (e.g. when a user presses a "submit" button or something similar in a HTML form).
In that case you can have multiple users requesting the webpage simultaneously. Also, you don't want to sleep in the thread serving the web page to the user. If you do that then there will be a delay where the user waits for the web page to respond while the SMS messages are sent.
I would suggest something like this:
When you need to send SMS messages you store the messages in a table in your database.
After storing new messages in the database you start a task (Task.Factory.StartNew) to process the SMS messages in the database.
You need to make sure that no more than one task is running in the ASP.NET application. Storing new messages in the database involves checking if the task is running and if not starting it.
The task will process all remaining messages in the database and send them using the appropriate delay (done by Thread.Sleeep).
When the task has sent an SMS message it is removed from the database.
This solution offloads the sending of messages to a background task that can be as slow as required and introduces persistence using the database to avoid loosing messages even if say the application pool is recycled.
Thread.Sleep is more appropriate, because it models better the waiting aspect.
Thread.Sleep() should be a good choice to delay calling to SMS gateway to prevent server reject your request.
I don't think it's Thread.Sleep() that's tying up the CPU.
Thread.Sleep seems bad design. Please refer http://blogs.msmvps.com/peterritchie/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program/ about why Thread.sleep is a bad.
Timer are more accurate, Thread.Sleep is only guaranteed to wait at LEAST as long as the amount of time you specify (the OS may put it to sleep for much longer). .

What's the best way to send large amounts of email via C# Web page?

I have part of a project whereby I need to send 1 to up to 2000 emails from a webpage. One open source bug tracker used a Thread to send emails but it was riddled with bugs.
So just want to know if anyone has any ideas of how I can create a procedure that send up to 2000 emails a go?
I was told by one of my colleagues to leave it as one process (normal routine sending one email at a time) as it won't take long to process all the emails anyway. Doesn't seem right and I want to use threading... maybe I like complex routines?
[Extra]
I have something like:
foreach(string email in emailAddresses)
{
MailMessage mailMessage = new MailMessage();
mailMessage.To.Add(...)
...
SmtpClient client = new SmtpClient();
client.Send(mailMessage);
}
Use System.Net.Mail to send the messages; however you should use .NET 4 to avoid any connection issues, as there was a bug filed on the Connect website that will cause your messages to not get sent.
Don't use threading for three reasons:
Reason 1: A MTA is made to handle message retries and can handle failures. Your code may not be robust enough to handle this. System.Net.Mail is not able to do this out of the box.
Reason 2: If you do use threading, you will overwhelm the target SMTP server and it will block you. Most Windows SMTP relays have a default block of more than 15 (or 25?) concurrent connections.
If you're dealing with Exchange 2010, or 2007, then there is a throttling feature that gets activated if you send more than x messages per minute. This is a per MTA setting that will need to be adjusted to permit your situation.
Reason 3: The preferred way to do this is to have a dedicated IIS SMTP server (or Exchange...) that allows concurrent connections at high volume. Just use Sys.Net.Mail to hand the delivery task to the mail infrastructure. Not much is needed for a mail infrastructure. Just have a MTA that allows you to relay and it will "smart host" on your behalf out to the internet.
More questions on how to set up the MTA can be answered # serverfault.
However
You may want to use threading if your sending an email from an ASP.NET webpage... or will otherwise block the UI. Other than that, I don't see a need to run concurrent threads for the email generation task.
Lastly, if you're sending the same message to many recipients, you can either use a distribution list or append many target recipients to the same message.
You probably don't want to send 2000 emails on a thread that is servicing http requests. The user that submitted the request will be waiting for the server to respond until the emails send, and that's one less thread available for processing requests from other users. If you have many such requests it could drag down server performance.
Instead, I would post the request to a message queue, and have a seperate service process items from the queue and send emails.
Creating background threads in the asp.net app is another possibility, but then you end up in a situation where either:
You have to have your own task queue , separate from the one used by the normal thread pool.
Your email tasks are competing with, and potentially starving, the tasks for serving http requests.
That being said, there are deployment scenarios (a shared server, customer deployments) where the introduction of a second process is not desirable. If you don't have those constraints, however, I would go with the "separate process" because it's easier to scale your web site if it's focused on serving UI requests and leaves "fulfillment" tasks to a different service.
I think 2000 will take a long time (if it's a web page and the user is waiting for the page). It depends on your implementation, but you're doing this frequently you might want to have a "email thread" that's already been created. If there are no emails to send, then the thread can be suspended and not be consuming any resources. Then when the emails need to be sent you fill up an email queue with those emails and wake up the thread to start sending (if it is not already doing so).
If you're sending more than about 50 at a time, you need to contract out to a service that does this for you. Otherwise your messages will end up in people's spam folders.

Categories