Resolves#101.
Since we now have full control over the SMTP client we can also access the message input and output.
This PR introduces a new debug logging feature. Via the `Client.WithDebugLog` the user can enable this feature. It will then make use of the new `smtp/Client.SetDebugLog` method. Once the flag is set to true, the SMTP client will start logging incoming and outgoing messages to os.Stderr.
Log directions will be output accordingly
- Also import the original BSD-3-Clause.txt license from the Go team into the LICENSES directory
- Further on, license headers should hold "The go-mail Authors" instead of my name. Did this already for the MIT license.
As part of #97 we are going to fork the official `net/smtp` package into go-mail to provide us with more flexibility.
This commit fulfills the first big step of importing the package into smtp/. Also go-mail's own LoginAuth has been moved from auth/ into smtp/ to be consistent with the stdlib.
There are still a couple of open issues (i. e. license adjustments and making golangci-lint happy) but so far all tests already work, which is a good start.
This fixes#94 and basically reverts d0f0435. As James points out correctly in #94, we should not assume specific responses from the server. As long as the spec is followed and the server returns the correct SMTP code, we should not do our own magic.
I've also extended the `getTestConnection` method in client_test.go, so that we can specify more test environment options like `TEST_PORT` and `TEST_TLS_SKIP_VERIFY`. This was needed for testing with the ProtonMail Bridge which listens on a different port and has non-trusted certificates.
As proposed by @iwittkau the `SendError` type now has a `IsTemp()` method as well indicating to the user if the delivery error is retryable or not.
Since we want to use it in the error response from the Client functions like `Send` or `DialAndSend` we need to return the SendError type not only as part of the `*Msg` but also as return value for these methods. Hence, the changes made for #85 been overhauled to return the new error type instead. In the pre Go1.20 version of the `Send()` method we need to return an accumulated version of the SendError type, since we don't have `errors.Join()` and therefore, if more than one error occurred during the delivery we return an ambiguous error reason since we can't tell which of the captured errors is main error. For more details the user can always check the `*Msg.SendError`
Not that this particular part of the code is performance critical, but I figured that the `strconv.Atoi()` is actually useless in here.
Since all we want to know is if the error code from the SMTP server is a 4xx error, we can just check the first rune of the returned error. The `Atoi` provides us with no advantage over the simple rune compare (except of taking about 3ns longer to execute)
Did a complete overhaul of the senderror.go.
- the list of `errors.New()` has been replaced with constant itoa error reasons as `SendErrReason`. Instead, the `Error()` method now reports the corresponding error message based on the reason.
- The `SendError` received a `Is()` method so that we can use `errors.Is()` for very specific error checking. I.e. we can check for `&SendErrors{Reason: ErrSMTPMailFrom, isTemp: true}`. This provides much more flexibility in the error checking capabilities
- A `isTemp` field has been added to the `SendError` type, indicating whether the received error is temporary and can be retried or not. Accordingly, the `*Msg` now has a `SendErrorIsTemp()` method indicating the same. The decision is based on the first 3 characters returned from the SMTP server. If the error code is within the 4xx range, the error is seen as temporary
- A test for the SendError type has been added
Since the send error indicate an error during the mail delivery, in my opinion it should be reset when a re-send is initiated, so that the senderror field always represents the latest delivery error. The send error should be checked after mail delivery and before a retry is started.
This PR introduces the `SendError` type which implements the error interface.
A new `senderror` field has been added to the `Msg` as well, so introduce this type to it.
I've also added different error variables that indicate the different things that can go wrong during mail delivery. These variables can be checked for, for each `Msg` using the `errors.As` method
The `Error()` method of `SendError` will return a detailed error string on why the `Msg` could not be delivered.
Additionally, `HasSendError()` and `SendError()` methods have been added to `Msg`. While `HasSendError()` simply returns a bool in case a `Msg` failed during delivery, the `SendError()` will return the full `SendError` error interface.