In case of an error, Smtp class by default throws an exception (like all other classes of MailBee.NET do). Although you can disable exceptions using Smtp.ThrowExceptions property if you don't like them, it's not recommended as it may hide some errors which would remain untrapped.
This guide mainly contains the technical background. For the code samples, see Exceptions and errors and TestSend example topics.
MailBee.NET provides an extremely manifold system of exceptions. This lets you programmatically catch exceptions you expect and leave other exceptions unhandled (so that if an unexpected exception occurs, you'd see the program break on it instead of erroneous behavior when this exception is caught by the handler intended for other exception, and unpredictable results occur).
The base is MailBeeException. Some of its descendants such as MailBeeInvalidArgumentException and MailBeeInvalidStateException usually indicate errors in your code and cannot be disabled even if you set Smtp.ThrowExceptions property value to false. Other exceptions can occur due to external factors like network, file I/O and data format errors.
Some exceptions provide a lot of additional information besides the human-readable message. This allows your application to respond to the exception programmatically (for instance, the application can display the text of an error message from the server or the numeric error code of a Win32 error).
All exceptions deriving from MailBeeException support MailBeeException.ErrorCode property which is another method of how you can determine which error occurred. The list of error codes is available in ErrorCodes class.
Note that some exceptions can have more than one error code associated with them (and thus an error code can be more specific to the particular error than just an exception type). See TestSend Example topic for the sample code.
Error messages associated with error codes are defined in Resources class. This class can be inherited so that you can adjust some (or all) error codes along with other strings like log file messages. For instance, you may want to translate the error messages to your local language. Of course, only MailBee.NET's own messages can be translated. Many exceptions include in their text the messages from their inner exceptions and these inner exceptions are thrown by .NET Framework itself. Their language will depend on the localization of the particular .NET Framework installation.
MailBeeException.ErrorCode property can be not the only error code associated with the given exception. Some exceptions provide additional codes specific to their context. For instance,MailBeeSmtpNegativeResponseException.ResponseCode property gets the SMTP error code of the last response from the server.
Network-related exceptions can be of two kinds:
To check if the connection is still valid after the exception, you can use Smtp.IsConnected property. Also, all exceptions which indicate the connection is no longer usable implement IMailBeeSocketMustCloseException interface (after such exceptions, Smtp.IsConnected is always false).
If the connection is valid after the exception, you can send other commands if you wish. If you don't, you should issue Smtp.Disconnect method in case if you manually called Smtp.Connect to start the SMTP session (i.e. the same procedure to follow as if no exception would have occurred at all).
In other words, a protocol-level exception does not leave any negative impact on the connection and if you caught it, you can continue as if nothing had happened.
However, please note that some servers drop the connection in addition to returning a negative reply. If this happens, you'll of course need to reconnect.
When you send a single e-mail through a single SMTP relay server, any error is a show stopper (aside from the case when SmtpServer.IgnoreLoginFailure is true and the authentication error occurs).
However, if you send through multiple servers (mailer.SmtpServers.Count > 1
, assuming mailer
is an Smtp instance) or send multiple e-mails with a method like Smtp.SendJobs, a single error does not yet indicate the entire operation has failed.
MailBee.NET won't throw an exception if the occurred problem either affects only a particular operation within the complex process or it can be overcome with another attempt (for instance, backup SMTP relay server was able to successfully deliver the message, the DNS server has responded at the second time, etc).
Still, to inform you that things are not perfectly good, MailBee.NET raises Smtp.ErrorOccurred event in every case when an internal exception occurs and gets caught by MailBee.NET itself. Also, MailBee.NET raises this event in case of a "real" exception which will then be re-thrown to your application.
Thus, two kinds of Smtp.ErrorOccurred events exist:
To let the application distinguish between those kinds of Smtp.ErrorOccurred events, its event argument includes ErrorEventArgs.IsFinalError property. If IsFinalError is false, this is just a warning, not a real error yet.
The meaning of warning, however, is quite relative. If you call Smtp.Send to send a single e-mail, it would be a warning if the message failed to be sent through the main relay server (but we have a backup server still to try). But if the e-mail fails completely (e.g. we have no backup server or it failed either), this will be a real error. However, in case of Smtp.SendJobs which can send multiple e-mails, even the total failure of a single e-mail won't stop the entire process and will be considered warning.
If you need to know exactly if certain e-mail in a series has been sent or not, use Smtp.MessageSent, Smtp.MessageNotSent, or Smtp.FinishingJob events. We assume that the method you're using to send the series of e-mails is a method like Smtp.SendJobs or Smtp.SendMailMerge (rather than multiple calls of Smtp.Send method).
For the sample code, refer to Monitor mail merge progress and track successful and failed sendings topic.
In the event handler, you can access the exception which prevented the e-mail from being sent to all or some recipients, via Reason property of the event parameters object (for instance, SmtpMessageNotSentEventArgs.Reason in case of Smtp.MessageNotSent event and ErrorEventArgs.Reason for Smtp.ErrorOccurred event).
Also, in case of Smtp.SendJobs and similar methods, the exception objects are saved in SendMailJob.ErrorReason property of every job in Smtp.JobsFailed collection (which you can examine during or after execution of Smtp.SendJobs method). Thus, you can analyze failures even not using events at all, just by iterating through this collection.
When using deprecated BeginXXX/EndXXX
async methods and callback functions, it's important to catch exceptions. If you don't catch exceptions, the async callback will silently terminate in case of an error. This happens because an unhandled exception which occurred on a worker thread terminates only that thread, not the entire application and its main thread. The application will never know what happened. To avoid this, all samples is this guide do catch exceptions.
The same is true for modern async/await
methods (with XXXAsync names). Although they are easier to use in many aspects, not handling an exception may have the effect when the current action (such as button click) does seemingly nothing to the user.
The console sample below was created from the internal implementation of Smtp.TestSend method. It shows the meaning of various exceptions and error codes of MailBee.NET and how they match TestSendResult values:
using System; using MailBee; using MailBee.Mime; using MailBee.Pop3Mail; using MailBee.DnsMX; using MailBee.SmtpMail; class Sample { static void Main(string[] args) { Smtp mailer = new Smtp(); // To make an exception get thrown, use wrong password. mailer.SmtpServers.Add("smtp.here.com", "joe", "bad password"); // Prepare a simple e-mail. mailer.Message.From = new EmailAddress("joe@here.com"); mailer.Message.To.Add("bill@there.com"); mailer.Message.Subject = "Test message"; TestSendResult result = TestSendResult.OK; try { // And try to send it. mailer.Send(); } catch (MailBeeInvalidArgumentException e) { if (e.ErrorCode == ErrorCodes.NoSender) { result = TestSendResult.NoSender; } else if (e.ErrorCode == ErrorCodes.NoRecipients) { result = TestSendResult.NoRecipients; } else if (e.ErrorCode == ErrorCodes.EmptyHostNameForDnsQuery) { result = TestSendResult.NoDomainInRecipientEmail; } else { result = TestSendResult.UnknownError; } } catch (MailBeeSmtpRefusedSenderException) { result = TestSendResult.BadSender; } catch (MailBeeSmtpRefusedRecipientException) { result = TestSendResult.BadRecipient; } catch (MailBeeSmtpNoAcceptedRecipientsException) { result = TestSendResult.NoAcceptedRecipients; } catch (MailBeeLoginNoCredentialsException) { result = TestSendResult.NoCredentials; } catch (MailBeeLoginNoSupportedMethodsException) { result = TestSendResult.NoSupportedAuth; } catch (MailBeeSmtpLoginBadMethodException) { result = TestSendResult.BadAuthMethod; } catch (MailBeeSmtpLoginBadCredentialsException) { result = TestSendResult.BadCredentials; } catch (MailBeePop3LoginBadCredentialsException) { result = TestSendResult.BadCredentials; } catch (MailBeeSmtpNegativeResponseException) { result = TestSendResult.NegativeSmtpResponse; } catch (MailBeePop3NegativeResponseException) { result = TestSendResult.NegativePop3Response; } catch (MailBeeDnsNameErrorException) { result = TestSendResult.NoMXRecord; } catch (MailBeeDnsProtocolException) { result = TestSendResult.DnsProtocolError; } catch (MailBeeConnectionException e) { switch (e.Protocol) { case TopLevelProtocolType.Smtp: result = TestSendResult.SmtpConnectionError; break; case TopLevelProtocolType.Dns: result = TestSendResult.DnsConnectionError; break; case TopLevelProtocolType.Pop3: result = TestSendResult.Pop3ConnectionError; break; default: result = TestSendResult.UnknownError; break; } } catch (MailBeeGetRemoteHostNameException e) { switch (e.HostProtocol) { case TopLevelProtocolType.Smtp: result = TestSendResult.SmtpResolveHostError; break; case TopLevelProtocolType.Pop3: result = TestSendResult.Pop3ResolveHostError; break; default: result = TestSendResult.UnknownError; break; } } catch (MailBeeException) { result = TestSendResult.UnknownError; } // Display the result of sending attempt. // For instance, if the client successfully connects with // the server but the server says the login or password // is incorrect, will display BadCredentials. Console.WriteLine(result.ToString()); } }
Imports System Imports MailBee Imports MailBee.Mime Imports MailBee.Pop3Mail Imports MailBee.DnsMX Imports MailBee.SmtpMail Module Module1 Sub Main() Dim mailer As New Smtp() ' To make an exception get thrown, use wrong password. mailer.SmtpServers.Add("smtp.here.com", "joe", "bad password") ' Prepare a simple e-mail. mailer.Message.From = New EmailAddress("joe@here.com") mailer.Message.To.Add("bill@there.com") mailer.Message.Subject = "Test message" Dim result As TestSendResult = TestSendResult.OK Try ' And try to send it. mailer.Send() Catch e As MailBeeInvalidArgumentException If e.ErrorCode = ErrorCodes.NoSender Then result = TestSendResult.NoSender Else If e.ErrorCode = ErrorCodes.NoRecipients Then result = TestSendResult.NoRecipients Else If e.ErrorCode = ErrorCodes.EmptyHostNameForDnsQuery Then result = TestSendResult.NoDomainInRecipientEmail Else result = TestSendResult.UnknownError End If End If End If Catch e As MailBeeSmtpRefusedSenderException result = TestSendResult.BadSender Catch e As MailBeeSmtpRefusedRecipientException result = TestSendResult.BadRecipient Catch e As MailBeeSmtpNoAcceptedRecipientsException result = TestSendResult.NoAcceptedRecipients Catch e As MailBeeLoginNoCredentialsException result = TestSendResult.NoCredentials Catch e As MailBeeLoginNoSupportedMethodsException result = TestSendResult.NoSupportedAuth Catch e As MailBeeSmtpLoginBadMethodException result = TestSendResult.BadAuthMethod Catch e As MailBeeSmtpLoginBadCredentialsException result = TestSendResult.BadCredentials Catch e As MailBeePop3LoginBadCredentialsException result = TestSendResult.BadCredentials Catch e As MailBeeSmtpNegativeResponseException result = TestSendResult.NegativeSmtpResponse Catch e As MailBeePop3NegativeResponseException result = TestSendResult.NegativePop3Response Catch e As MailBeeDnsNameErrorException result = TestSendResult.NoMXRecord Catch e As MailBeeDnsProtocolException result = TestSendResult.DnsProtocolError Catch e As MailBeeConnectionException Select Case e.Protocol Case TopLevelProtocolType.Smtp result = TestSendResult.SmtpConnectionError Case TopLevelProtocolType.Dns result = TestSendResult.DnsConnectionError Case TopLevelProtocolType.Pop3 result = TestSendResult.Pop3ConnectionError Case Else result = TestSendResult.UnknownError End Select Catch e As MailBeeGetRemoteHostNameException Select Case e.HostProtocol Case TopLevelProtocolType.Smtp result = TestSendResult.SmtpResolveHostError Case TopLevelProtocolType.Pop3 result = TestSendResult.Pop3ResolveHostError Case Else result = TestSendResult.UnknownError End Select Catch e As MailBeeException result = TestSendResult.UnknownError End Try ' Display the result of sending attempt. ' For instance, if the client successfully connects with ' the server but the server says the login or password ' is incorrect, will display BadCredentials. Console.WriteLine(result.ToString()) End Sub End Module
This code above is for demonstration purposes only, you don't need it for testing e-mail addresses as you can use Smtp.TestSend method itself (or EmailAddressValidator component if you need to verify lots of addresses).
You can find more examples of exception processing with MailBee.NET in Exceptions and errors, Get DNS MX records, Send single e-mail asynchronously topics.
Copyright © 2006-2024 AfterLogic Corporation. All rights reserved.