I made a simple notifier command line application in C#. Basically I use the windows task scheduler and set it up to run this command line application at a certain time.
When this time is hit the command line application is ran all notifications are grabbed from a database(using linq to sql) formatted and sent by smtp to the right people.
Now how should I handle these scenarios
A database error occurs
Solution: Send a email to the admin to notify them that it failed and to check it out.
A smtp error occurs
Solution: ?????
So these are really the two things that could go wrong. There could be different combination's of this.
Database error might occur and and smtp might occur too, Or only one or the other might occur.
So how to get this information to an admin or someone so they can fix it. I highly doubt that an admin would go and check every single day to see if the notification thing worked or not.
So basically how to make it fail safe or at least make it so that if something goes wrong a admin can come fix and it and just run the notifier manually and get everything back in sync.
You have a couple options.
Write the error information to a log. Make it a procedure for some operator to check the log every so often.
Have it call some other service?
However, if the database is used by more than just your app, it's entirely possible that someone else will notice. Same thing with the email server. If it's down, then I bet a lot of people will be making phone calls. Note that your situation precludes lost network connectivity (like a dead switch or misconfigured router).
Incidentally if it detects SMTP is back up, then it should notify someone that it was down for a given time period. Same thing about the database server.
Finally, ALL error conditions should be written to your system log. It's pretty trivial to write to the windows event logs. If your system administrators are following commonly accepted protocols they should be monitoring those pretty often anyway.
Logging an Error to the EventLog could also be an option, providing that the Admin either checks the EventLog regularly or that you have monitoring systems that aggregate those errors.
You could use an SMS gateway or attach a cellphone to the server and have it send a text message to an admin when something has gone horribly wrong.
But you can take this even further:
What if you lose network connectivity
(a switch or cable gone bad for
example)?
What if the power goes down
(when is the last time you tested the
UPS)?
Depending on your needs (and the business cost of not sending out these notifications in short notice), you may need a full-fledged monitoring solution.
So the main problem is that you do not know how to notify the admin in case of an SMTP server failure. You have several options, assuming the admin's e-mail account is not residing on the same server.
First option: You could set up a cgi mail script on another server and contact that via http to send the e-mail.
Second option: Use an smtp client and set it up to contact the receiver's smtp server for sending the e-mail directly (instead of going through the local smtp server).
BTW: Some e-mail providers offer text message notifications for e-mails originating from a certain address. That's very handy if the server goes down while the admin is away from his desk.
For your DB errors, you could hardcode in a (set of) email address for DB errors to be sent to.
As for the SMTP errors, you can either do a "send email when smtp recovers", or you have to have an alternate method for alerting your admins. This could be a backup SMTP server, a SMS gateway (as someone else mentioned), or even something such as someones desktop in the network popping up an alert if it doesn't receive some type of "everything is ok" alert/message from the box running the script.
Related
I've written a component in a Windows service (C#) which is responsible for sending sometimes large volumes of emails. These emails will go to recipients on many domains – really, any domain. (Yes, the recipients want the email. No, I'm not spamming. Yes, I'm in complaince with CAN-SPAM. Yes, I'm aware sending email from code sucks.) Many of the emails are transactional (generated in response to user actions); some are bulk (mail-merges basically).
I do not want to rely on an external SMTP server. (Among other considerations, the thought of having to check a mailbox for bounce messages and trying to parse them gives me bad feelings.)
My design is fairly simple. Both the transactional and bulk messages are generated and inserted into a DB table. This table contains the email envelope and content, plus an attempt count and retry-after date.
The service runs a few worker threads which grab 20 rows at a time and loop through each. Using the Simple DNS Plus library, I grab the MX record(s) of the recipient's domain and then use System.Net.Mail.SmtpClient to synchronously send the email. If the call to Send() succeeds, I can dequeue the email. If it temporarily fails, I can increment the attempt count and set an appropriate retry-after date. If it permanently fails, I can dequeue and handle the failure.
Obviously, sending thousands of test emails to hundreds of different actual domains is a Very Bad Idea. However, I definitely need to stress-test my multi-threaded send code. I'm also not quite sure what the best way is to simulate the various failure modes of SMTP. Plus, I want to make sure I get past the various spam control methods (graylisting to name the most relevant to the network layer of things).
Even my small-scale testing difficulties are exacerbated by my recent discovery of my ISP blocking connections to port 25 on any server other than my ISP's SMTP server. (In production, this thing will of course be on a proper server where port 25 isn't blocked. That does not help me test from my dev machine.)
So, the two things I'm most curious about:
How should I go about testing my code?
What are the various ways that SmtpClient.Send() can fail? Six exceptions are listed; SmtpException and SmtpFailedRecipientsException seem to be the most relevant.
Update: Marc B's answer points out that I'm basically creating my own SMTP server. He makes the valid point that I'm reinventing the wheel, so here's my rationale for not using an 'actual' one (Postfix, etc) instead:
Emails have different send priorities (though this is unrelated to the envelope's X-Priority). Bulk email is low priority; transactional is high. (And any email or group of emails can be further configured to have an arbitrary priority.) I need to be able to suspend the sending of lower-priority emails so higher-priority emails can be delivered first. (To accomplish this, the worker threads simply pick up the highest priority items from the queue each time they get another 20.)
If I've already submitted several thousand bulk items to an external SMTP server, I have no way of putting those on hold while the items I wish to submit now get sent. A cursory Google search shows Postfix doesn't really support priorities; Sendmail prioritizes on information in the envelope, which does not meet my needs.
I need to be able to display the progress of the send process of a blast (group of bulk emails) to my users. If I've simply handed all of my emails off to an external server, I have no idea how far along in actual delivery it is.
I'm hesitant to parse bounce messages because each MTA's bounce message is different. Sendmail's is different from Exchange's is different from [...]. Also, at what frequency do I check my bounce inbox? What if a bounce message itself isn't delivered?
I'm not too terribly concerned with a blast failing half-way through.
If we're talking catastrophic failure (app-terminating unhandled exception, power failure, whatever): Since the worker threads dequeue each email from the database when it is successfully delivered, I can know who has received the blast and who hasn't. Further, when the service resets after a failure, it simply picks up where it left off in the queue.
If we're talking local failure (a SmtpException, DNS failure, or so forth): I just log the failure, increment the email's attempt counter, and try again later. (Which is basically what the SMTP spec calls for.) After n attempts, I can permanently fail the message (dequeue it) and log the failure for examination later. This way, I can find weird edge cases that my code isn't handling – even if my code isn't 100% perfect the first time. (And let's be honest, it won't be.)
I'm hoping the roll-my-own route will ultimately allow me to get emails out faster than if I had to rely on an external SMTP server. I'd have to worry about rate-limiting if the server weren't under my control; even if it were, it's still a bottleneck. The multithreaded architecture I've gone with means I'm connecting to multiple remote servers in parallel, decreasing the total amount of time it takes to deliver n messages.
Assume you've got two servers available. One will be the sender, one will be the receiver. You can set up DNS (or even just hosts files) on both with a long series of fake domains. As far as the two servers are concerned, those domains are perfectly valid as the local DNS servers are authoritative for them, but are completely invalid as far as the rest of the net is concerned. Just make sure the resolver checks the hosts file before DNS.
Once that's done, you can have the sending server spam the receiving server to your heart's content, as have the receiver do various things to test your code's reactions. Greylisting, TCP delays, hard bounces, ICMP unreachables, ICMP hops exceeded, etc...
Of course, given you have to test all these conditions, you're basically creating your own SMTP server, so why not use an actual one to begin with? I'd guess the effort required to do some basic parseing of bounce messages will be far less than having to come up with code chunks to handle all the failure modes that postfix/sendmail/exim/etc... already handle perfectly well on their own.
And this is especially true when you consider your sending code has to be perfect from the get-go. If an email blast fails part-way through and only half the recipient list gets the message, you're in a far bigger hole than if a few hundred or a few thousand messages bounce. Or worse yet, fails in multiple different ways (some servers unreachable, some greylisting you for excessive traffic, etc...). Whereas bounces will happily sit in the incoming queue until you process them manually, or patch up your bounce parser to handle them.
After searching around, I ended up firing up Papercut on several extra machines I had laying around. I then populated my database with test addresses *#[test-machine-*.local].
While this did work well enough, I tested with 25 send threads and it looked like I was overwhelming the four computers running Papercut. Several hundred send attempts experienced TCP connection failures; those messages were properly requeued to be sent later (and ultimately did arrive). However, out of 25,000 test emails, about 500 simply disappeared – adding up the *.eml files in Papercut's folder on each test machine yielded only ~24,500.
Now I'm left wondering whether the missing emails are a due to a problem in my code, or if Papercut dropped messages which it reported in SMTP as 250 OK.
I have an application with a static class that is capturing all errors that happens during the runtime (if its the case) and when process is done, it sends out an email with the list of errors so I or any other developers can address those errors.
However my problem is that McAfee is blocking the request, as if it was a kind of virus. I do not have rights on my machine to edit McAfee settings, is it possible to fix it through C# code?
Thank you
Probably McAfee is blocking outgoing connections on port 25 (SMTP), only allowing a white list of applications to send email.
What you can do is:
Put the email in a mailto:// url. Execute the mailto:// as if it is a normal command line. This will ask for input from the user, but you can create a nice template for the user. (syntax)
Send the email through your normal email client (Outlook, Notes), if they have an API for that.
Use a Http/Web based provider that has an API. Public ones are probably also blocked by McAfee. But you could create & host a service yourself. Be very carefull to only allow traffic from within your company.
Maybe you company has a "drop folder", where you can drop emails that are picked up by the email server.
Depending on what/why McAfee is flagging it, more than likely you will not be able to get around it.
You will want to see if you can find out if McAfee is flagging it due to the port being used, or if there is any other information as to why the individual message is not going.
No. And yes.
No, you can't force McAffee to not flag your email from code, if that's what you mean.
Yes, you can prevent McAffee or other virus scanners from flagging your emails as suspicious. Here are a couple of things I try to make sure of:
That your all addresses (especially from: and reply-to:) are valid.
That the the name you're sending from is actually the name of a the correct person in your active directory.
You could also ask your system administrators to put your "from:" address on a global whitelist so that it always goes to the client.
Are you attaching executables? Are you sure you aren't attaching any viruses? ;-)
From what I recall, I think McAfee has a list of programmes that are allowed to send emails, if your program is not added to this list, then your emails will not get sent.
This is a big support problem, as you will find your customers have a 101 different virus checkers all setup in different ways.
You may be able to setup a email server to use a none standard port, then send emails to that port.
For testing, attaching to the McAfee process with a debugger and then killing it can work well...
I have some of the basic coding down for the program but I do need assistance with something. My goal is to have an alarm go off on multiple PCs in a network indicating that a certain task needs done. Anyone who receives this alarm may stop it, complete the task and log that they did that. What would be the best way to accomplish this in a network? But not every computer in the network will be running this program, just a few.
You could have the application (which runs on some computers in the network) register to participate in a Multicast address. This would allow the machines in the network to exchange data without the need for a central server.
More information:
IP Multicasting: http://en.wikipedia.org/wiki/Multicast
Multicasting in C#: (CodeProject) http://www.codeproject.com/KB/IP/multicast.aspx
Example project: http://www.nmsl.cs.ucsb.edu/MulticastSocketsBook/csharp_send_receive.zip
You would have the program that generates the alarm send out a multicast message
containing all the information required by the other computers to handle the task.
The computers who can execute the job send back a message and the alarm application
then decides which "client" will eventually execute the task by sending that client a "go ahead and do it" message. Only then the "client" application would actually perform the task and report back when it's finished.
Just an idea.
You could also make a web page on the management server where the visiting users can register for alarms. This would mean that you develop and distribute to one computer instead of x number of computers. The alarm would then go off in your web browser, where the users would also respond.
you can have a process listen on the other PCs on a socket, which triggers the alarm.
http://www.devarticles.com/c/a/C-Sharp/Socket-Programming-in-C-sharp-Part-II/1/
In a corporate environment (or possibly some schools), this is a very common IT problem. You'd use their IT deployment/policy enforcement software to distribute the program.
If you're in control of your network environment, then distribute it however seems fit. An intranet web page where you subscribe to alerts makes sense, as Patrick answered.
Doing a push across the network seems unreliable, and would definitely anger IT staff if you ever moved your program into a less friendly network :) Plus, it simply is the wrong model for the job if your network is the internet.
Is it possible to write C# code as below and send email using mnetwork in different country?
MSExchangeWebServiceURL = mail.something.com/ews/exchange.asmx
It's a web service URL. This works great when I run the same code from home network, my friends home network anywhere around, but when I run it from my client's location in Columbia it fails.
I have a valid user name and password on that Exchange Server. Is there any configuration that I can set to achieve this?
BTW this code below works when I run it within office network and any network within any home network. I have tried it at least with five friends network in Plano, Texas. I want this code to work running from any network in another country.
My client in Columbia can connect to the web service using a browser using the same user name and password, but when I run the code above it is not able to connect to our web service.
EDIT: Based on the comments and updated post, I would wager that the client location has a proxy server or firewall that is blocking the traffic. The client probably needs to add the relevant domain to whatever "whitelist" they have.
If it works from an internal network, then the problem is most likely not the code. You need to debug it and see what error turns up when running it outside of the network. Then check the logs on the firewall and the target exchange server to see what is happening.
One possible culprit is that the DNS name is not setup outside the office network, or that the office firewall is not setup to pass traffic (or only to pass SMTP traffic) from the internet to the server in question. Another is that Exchange Web Services is not setup properly to accept requests from the outside world. That can be tested from http://www.testexchangeconnectivity.com/.
If this isn't enough for you to get there, post more info about what errors you are seeing. "It isn't working, I want it to work" kind of reminds me of the Star Trek TNG episode about the species who kept telling Geordi to "make it go".
If you are asking if the code works (which it doesn't look like you are but it's in your post) you should ask on stackoverflow. If you are wondering why it won't work from home Its likely because the edge server is not set up to relay, and if you are at home and not vpn'd into the network that's all you have access to.
You need to break this down a bit:
What's the MSExchangeWebServiceURL? I don't need to know your real URL, but is this resolvable from your home network? i.e. is it an internal DNS host (server.mycompany.local) or is it an externally-resolvable DNS host (mail.yourcompany.com)?
If it's internal, like another poster said, you'll at least need to VPN in (or replace that with the external URL).
I'm not a big C# guy, but I'm guessing it's looking for your Exchange Server hostname or FQDN, and since the type is "SMTP" it wants to establish a TCP session with your mail server. You can likely test this out by opening up your command prompt and trying to telnet <MSExchangeWebServiceURL> 25. When that works, my guess is your code will work too.
Our e-commerce site requires the sending of email
Currently, for some odd reason, the server that is being used to do this is the database server... which clearly isn't ideal (i've just taken over here)
My idea is this -
to write a windows service that checks for new mails that need sending (these are all in a sql db) and then process the mails seperately...
I want to use a seperate mail server, to keep this efficient..
Has anyone had any experience of this?
Would it be sensible to (for example) set up a lightweight debian (or other distro) machine, with exim on?
Would i be able to use that as the host ip address when specifying my smtp server to send email?
I'm going to be using C#....
I've done this quite a bit, and sometimes I've used a windows server running the SMTP service, other times we've used a third party. In either case you set the host of the mail server in the configuration file and your application can pick it up and continue working.
A nice thing about using a third party service, is that you should have less concern about being black listed.
We did something very similar. We used the IIS SMTP server and wrote code in C# to pump messages directly into its pickup directory using SmtpDeliveryMethod.PickupDirectoryFromIis. systemnetmail.com has some sample code that may help you.
One thing to be careful of is race conditions in the database, especially if you are sending messages with more than one thread (which we were doing). We implemented a queue in the database and used the UPDLOCK and READPAST hints in SQL Server for maximum performance. I think we got it up to over 10,000 emails a minute this way.
You can use the Windows SMTP server wich you can access and use from your web or console application using the CDOSYS or CDO object. You can use this link about configuring the SMTP server on Windows 2003