.NET email testing client - c#

There are times when an ASP.NET or other.NET app with System.Net.Mail.SmtpClient fails to send messages. It might be due to a recent server change, maybe the server now requires SSL, or the port changed, or it's a DNS issue, changed credentials, firewall, or new Anti-Malware definitions. Maybe the issue is specifically with GMail or AOL or another server type. To get closer to identifying the problem we can catch SmtpFailedRecipientException before SmtpException, then catch SocketException, and plain Exception last. That helps to narrow down the issue but it's still not specific enough.
I'm getting the itch to write a C# app that will allow an admin to test a number of permutations to see what works, using a table of common options as well as a UI to enter new params like port numbers or email address formats, etc. The result should be a specific result telling exactly what is wrong with the specs provided, or at least starting with "can't connect outside network", then "can't connect to remote host", or "host exists but can't connect to port", then "connected but can't authenticate", then "authenticated but 'something else failed'...".
But before I do this, I have to believe there's already some FOSS that's been written for us to build upon. Can anyone recommend such a beast? Thanks.

Related

OutboundSpamException when bulk(ish) sending emails from outlook account over outlook SMTP (C#/.NET)

I recently created an Azure function (C#) which sends me an email every morning at 8am with some information over SMTP using smtp.outlook.com. Some people I know heard about this and asked to be included on the mailing list. I created a new outlook account (e.g. myemailsenderxxx#outlook.com) specifically for this and it appeared to work okay whilst currently sending emails to about 15 people a day. However, I sometimes get the following exception whilst sending:
Transaction failed. The server response was: 5.2.0
STOREDRV.Submission.Exception:OutboundSpamException; Failed to process
message due to a permanent exception with message
[BeginDiagnosticData]WASCL UserAction verdict is not None. Actual
verdict is TransientError. OutboundSpamException: WASCL UserAction
verdict is not None. Actual verdict is
TransientError.[EndDiagnosticData]
[Hostname=CWXP265MB5768.GBRP265.PROD.OUTLOOK.COM]
I've done some research and my understanding is that free/personal outlook accounts shouldn't really be used for this, and that could be the reason why it's happening.
Is there a way I can prevent this happening with my current setup? There is a chance the mailing list could continue to grow a bit but it'll never get big. I have seen some recommendations to use an SMTP service provider, but they appear to cost money and since this is just a small fun project I don't want to pay anything ideally.
Any suggestions would be much appreciated.

Getting "The remote certificate is invalid according to the validation procedure" when SMTP server has a valid certificate

This seems a common error but while I've found a work-around (see below) I can't pin down the reason I'm getting it in the first place.
I am writing SMTP functionality into our application and I'm attempting to add SSL functionality to the working SMTP we already have.
I am testing using our company's MS Exchange server and specifically the webmail option enabled on that. I can send emails internally through my code by not authenticating my connection and sending anonymously, however those emails won't relay to external email addresses due to our companies policy. Besides which I am programming this for our customers and they don't all allow open relay and/or anonymous connections.
I believe the Exchange server is using Explicit SSL/ TLS. I have tried telnet to the server's address on port 25 and got a text response, human readable response, which according to some of my searches previously means it's using Explicit SSL/ TLS.
I have the following test code
SmtpClient SMTPClient = new SmtpClient(webmailaddress);
SMTPClient.Port = 25;
SMTPClient.UseDefaultCredentials = true;
SMTPClient.EnableSsl = true;
System.Net.Mail.MailMessage Message = new `
System.Net.Mail.MailMessage(emailFrom,emailTo,subject,body);
SMTPClient.Send(Message);
During my searching for a solution I came across this "The remote certificate is invalid according to the validation procedure." using Gmail SMTP server
From which I got the following code...
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
public static bool ValidateServerCertificate(object sender,X509Certificate certificate,X509Chain chain,SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
else
{
if (System.Windows.Forms.MessageBox.Show("The server certificate is not valid.\nAccept?", "Certificate Validation", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
return true;
else
return false;
}
}
This works in my test code. HOWEVER the actual process I'm writing (rather than my test code) is going to run in the background and can't really ask the user (instead it reports errors in the windows error log).
As I started, my question is really why I'm getting this error at all. If I go to https:webmail.ourdomain.co.uk in a browser it shows a valid certificate and there is no option to install the certificate (as I would have done if it were a self-signed one).
However when I run my code, with a debug break poing in the ValidateServerCertificate method, I look at the certificate values and see an issuer of our local server and 'don't use before', and 'don't use after' properties of today. This does not match the certificate I am getting.
I've also checked what the sslPolicyErrors flags are in the debug of ValidateServerCertificate, and they are showing "RemoteCertificateChainErrors" and "RemoteCertificateNameMismatch".
So what am I missing about this... why is it not using the correct certificate? If there are steps I need to take to install the certificate locally for it to use then I need to know them so I can tell my customers what to do if they get this.
I don't want to just by-pass the check by returning true from the ValidateServerCertificate method, and because it's a background process I can't ask the user, so I need to understand how to get my code to use the correct/trusted certificate.
Hope someone can advise.
The answer I have finally found is that the SMTP service on the server is not using the same certificate as https.
The diagnostic steps I had read here make the assumption they use the same certificate and every time I've tried this in the past they have done and the diagnostic steps are exactly what I've done to solve the problem several times.
In this case those steps didn't work because the certificates in use were different, and the possibility of this is something I had never come across.
The solution is either to export the actual certificate from the server and then install it as a trusted certificate on my machine, or to get a different valid/trusted certificate for the SMTP service on the server. That is currently with our IT department who administer the servers to decide which they want to do.
Old post but as you said "why is it not using the correct certificate" I would like to offer an way to find out which SSL certificate is used for SMTP (see here) which required openssl:
openssl s_client -connect exchange01.int.contoso.com:25 -starttls smtp
This will outline the used SSL certificate for the SMTP service. Based on what you see here you can replace the wrong certificate (like you already did) with a correct one (or trust the certificate manually).
Old post, but I thought I would share my solution because there aren't many solutions out there for this issue.
If you're running an old Windows Server 2003 machine, you likely need to install a hotfix (KB938397).
This problem occurs because the Cryptography API 2 (CAPI2) in Windows
Server 2003 does not support the SHA2 family of hashing algorithms.
CAPI2 is the part of the Cryptography API that handles certificates.
https://support.microsoft.com/en-us/kb/938397
For whatever reason, Microsoft wants to email you this hotfix instead of allowing you to download directly. Here's a direct link to the hotfix from the email:
http://hotfixv4.microsoft.com/Windows Server 2003/sp3/Fix200653/3790/free/315159_ENU_x64_zip.exe

SmtpClient get result from server on send

The SmtpClient send method returns void. Is there any way to get the server response? Do I just assume it was successful unless it throws an exception?
The class I'm referring to... http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.aspx
To answer your second point, yes, all you can do is assume it's successful - meaning it got the message to the server and the server accepted it, unless you get an exception.
You probably already know the rest of this, but just in case...
From there, the email could get lost and not delivered any number of ways. Your server may accept it and decide not to send it, or accept it and lose power before crashing. It may get blocked by a spam filter along the way, etc.
You can think of an email as being similar to a regular piece of mail in that it passes through several hands between the sender and the recipient. From your code, you can only confirm that it got to the SMTP server you're using to send, which is similar to handing it to a teller at the post office. You don't know (or need to know) how the message is routed from there. it could be by air, ground, or carrier pigeon. You're out of the equation - you don't need to know how it gets sent, just that you trust that they know how to send it. (The same can be said for an email.)
If you need to confirm that the recipient opened it, there are ways of embedding an image in an HTML message on your server and tracking in your logs when that image is accessed, etc. (Google email tracking and email open tracking)
On the other hand...
If the server rejects it, then you do get a server response in a manner of speaking - there should be an error code and a description in the error, which you can use to troubleshoot why it didn't make it, or use error handling to try another route, etc.
You can utilize SendCompleted Event to check that your smtpclient works fine like this:
http://msdn.microsoft.com/en-us/library/system.net.mail.smtpclient.sendcompleted.aspx
But you cannot get confirmation that your message reached recipient because it may stuck in any server/filter in message chain.
You assume that it was successful unless it throws... although success in this case only means that it was accepted by the mail server, anything else is then up to the server...
IF you want a little bit of control you can use SendAsync and hook the SendCompleted event...

Checking if a Mail Server uses SSL without trying to send an e-Mail

I'm using C#, and while working on a sending mail routine using the tools available on the .NET Framework and I've sumbled upon two situations
One mail server that requires SSL
One mail server that doesn't support SSL
So when using a generic mail sending tool, I've noticed that I should ask the user if SSL should be used, or figure it by coding.
When I try to send an E-Mail not using SSL through a mail server that requires it, I get an exception.
When I try to send an E-Mail using SSL through a mail server that doesnt support it, I get an exception.
By doing this, it should be easy to check wether I should use it or not.
But I want a smarter way to do this. I didn't find any way to do so. Is there one ?
Personally, I do not believe that your code should be "Automagically" determining if SSL should be used.
When the e-mail service is configured by the users, they should be telling you how it works and what is needed.
You can see this behavior by the way the out of the box .NET SMTP which you must tell it how it is.
To further this, some services have a different URL for SSL and non SSL, and maybe users SHOULD be using SSL, but you could let them accidentally send the wrong way.
bool supportsSSL = true;
Stream stream = new SslStream(client.GetStream(), false);
try
{
((SslStream)stream).AuthenticateAsClient("pop3.xyz.com");
}
catch (Exception e)
{
supportsSSL =false;
}
It sounds like you have the answer. As long as the SMTP library you are using does the right thing when throwing the exception, try ssl first, then fallback to non-ssl, and handle that error case (i.e. total failure) if it happens.
I think you are concerned because you don't know what's going on under the covers when the exception is thrown, and if that's so, I feel the same. I don't know if your .net toolkit provides the facilities, but you should be able to make the connection with a lower-level type connection object which allows you to test whether or not it's possible to make an ssl connection and check the return value of your attempt, then decide how to proceed based on that.
It may be more trouble than it's worth though, because you might then need to bolt on SMTP functionality to your new connection type, if your SMTP library doesn't support using an already established connection. Which is the long way around saying, you're probably doing well enough with catching the exception and trying again.
In reference to #Mitchel's answer, I'd say it's perfectly okay if it's automagic as long as the right notification is made, and of course the context is right. SMTP is still pretty often plain text, so any expectation of encryption for email is pretty low. Login credentials are another matter. If this is an app an end user would use, you certainly ought to make sure they're connecting over SSL if credentials will be exchanged.

What should the client do while the TIBCO EMS server attempts failover?

The TIBCO EMS user's guide (pg 292) says:
The backup server will work indefinitely to either A) become the
primary server or B) reconnect to the primary server. It also says
clients may receive fail-over notification when the switch is successful (see also TIBCO EMS .NET reference pg 220).
I have some questions spinning off of these facts...
What kind of errors occur on the client side while the servers are attempting fail-over/reconnect?
What is the appropriate response from the client?
Get new Connection objects from the ConnectionFactory until one works?
Wait for fail-over notification? (are current Connection instances fixed at this time? or do I need to get a new instance?)
I hope the scenario is clear, any related information or advice would be appreciated too.
I can at least answer #1 above.
If you have enabled Tibems.SetExceptionOnFTSwitch(true); and have set up an exception handler to capture the messages the server sends to the client, you will see the following:
For single-server, non-fault tolerant connection failures:
"Connection has been terminated".
For fault-tolerant connection failures:
"Connection has performed fault-tolerant switch to "
If you attempt to publish while the connection is down, a TIBCO.EMS.IllegalStateException is thrown with the "Producer is closed" message.
for #2 above, I think the answer is to allow the EMS library to handle as much as possible. Once we got the EMS reconnect functionality to work, it gracefully tried to reconnect until the server became available again and once it reconnected, it was like there was never a problem. The only gotcha is probably if you try to publish a message before the ems connection is back. This is where the exception handler comes in, Once notified that you are in failover mode, you can adjust exception handling on the publisher side to suppress the error until the connection is back. The thing I don't know is how do you tell when you've exhausted all reconnect attempts.
Anyway, Seems like our two worlds are closely related when it comes to EMS - hope our findings (based on your comments on my questions) help you.
We use TEMS (Tibco EMS - a Tibco Product for WCF) So it becomes a custom binding. We tried to break it by doing things like bounce the server to force switch overs and it works really well. make sure you are using version 1.2 not 1.1 because you cannot do anything other then client acknowledgement.

Categories