2023-01-15 16:14:19 +01:00
|
|
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
2022-12-31 12:47:20 +01:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2022-12-31 12:40:42 +01:00
|
|
|
package mail
|
|
|
|
|
|
|
|
import (
|
2023-01-01 14:25:00 +01:00
|
|
|
"errors"
|
2022-12-31 12:40:42 +01:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2023-01-01 14:20:13 +01:00
|
|
|
// List of SendError reasons
|
|
|
|
const (
|
2022-12-31 12:40:42 +01:00
|
|
|
// ErrGetSender is returned if the Msg.GetSender method fails during a Client.Send
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrGetSender SendErrReason = iota
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrGetRcpts is returned if the Msg.GetRecipients method fails during a Client.Send
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrGetRcpts
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrSMTPMailFrom is returned if the Msg delivery failed when sending the MAIL FROM command
|
|
|
|
// to the sending SMTP server
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrSMTPMailFrom
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrSMTPRcptTo is returned if the Msg delivery failed when sending the RCPT TO command
|
|
|
|
// to the sending SMTP server
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrSMTPRcptTo
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrSMTPData is returned if the Msg delivery failed when sending the DATA command
|
|
|
|
// to the sending SMTP server
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrSMTPData
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrSMTPDataClose is returned if the Msg delivery failed when trying to close the
|
|
|
|
// Client data writer
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrSMTPDataClose
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrSMTPReset is returned if the Msg delivery failed when sending the RSET command
|
|
|
|
// to the sending SMTP server
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrSMTPReset
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrWriteContent is returned if the Msg delivery failed when sending Msg content
|
|
|
|
// to the Client writer
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrWriteContent
|
2022-12-31 12:40:42 +01:00
|
|
|
|
|
|
|
// ErrConnCheck is returned if the Msg delivery failed when checking if the SMTP
|
|
|
|
// server connection is still working
|
2023-01-01 14:20:13 +01:00
|
|
|
ErrConnCheck
|
|
|
|
|
|
|
|
// ErrNoUnencoded is returned if the Msg delivery failed when the Msg is configured for
|
|
|
|
// unencoded delivery but the server does not support this
|
|
|
|
ErrNoUnencoded
|
2023-01-02 12:14:14 +01:00
|
|
|
|
|
|
|
// ErrAmbiguous is a generalized delivery error for the SendError type that is
|
|
|
|
// returned if the exact reason for the delivery failure is ambiguous
|
|
|
|
ErrAmbiguous
|
2022-12-31 12:40:42 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// SendError is an error wrapper for delivery errors of the Msg
|
|
|
|
type SendError struct {
|
2024-07-16 13:07:20 +02:00
|
|
|
affectedMsg *Msg
|
|
|
|
errlist []error
|
|
|
|
isTemp bool
|
|
|
|
rcpt []string
|
|
|
|
Reason SendErrReason
|
2022-12-31 12:40:42 +01:00
|
|
|
}
|
|
|
|
|
2023-01-01 14:20:13 +01:00
|
|
|
// SendErrReason represents a comparable reason on why the delivery failed
|
|
|
|
type SendErrReason int
|
|
|
|
|
2022-12-31 12:40:42 +01:00
|
|
|
// Error implements the error interface for the SendError type
|
2023-01-01 14:20:13 +01:00
|
|
|
func (e *SendError) Error() string {
|
2023-01-02 12:14:14 +01:00
|
|
|
if e.Reason > 10 {
|
2023-01-02 21:55:37 +01:00
|
|
|
return "unknown reason"
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
|
|
|
|
2024-02-27 11:32:12 +01:00
|
|
|
var errMessage strings.Builder
|
|
|
|
errMessage.WriteString(e.Reason.String())
|
2023-01-01 14:20:13 +01:00
|
|
|
if len(e.errlist) > 0 {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteRune(':')
|
2023-01-01 14:20:13 +01:00
|
|
|
for i := range e.errlist {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteRune(' ')
|
|
|
|
errMessage.WriteString(e.errlist[i].Error())
|
2023-01-01 14:20:13 +01:00
|
|
|
if i != len(e.errlist)-1 {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteString(", ")
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
2022-12-31 12:40:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(e.rcpt) > 0 {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteString(", affected recipient(s): ")
|
2022-12-31 12:40:42 +01:00
|
|
|
for i := range e.rcpt {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteString(e.rcpt[i])
|
2023-01-01 14:20:13 +01:00
|
|
|
if i != len(e.rcpt)-1 {
|
2024-02-27 11:32:12 +01:00
|
|
|
errMessage.WriteString(", ")
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
2022-12-31 12:40:42 +01:00
|
|
|
}
|
|
|
|
}
|
2024-09-19 12:12:48 +02:00
|
|
|
if e.affectedMsg != nil && e.affectedMsg.GetMessageID() != "" {
|
|
|
|
errMessage.WriteString(", affected message ID: ")
|
|
|
|
errMessage.WriteString(e.affectedMsg.GetMessageID())
|
|
|
|
}
|
|
|
|
|
2024-02-27 11:32:12 +01:00
|
|
|
return errMessage.String()
|
2022-12-31 12:40:42 +01:00
|
|
|
}
|
2023-01-01 14:20:13 +01:00
|
|
|
|
|
|
|
// Is implements the errors.Is functionality and compares the SendErrReason
|
2024-02-27 11:32:12 +01:00
|
|
|
func (e *SendError) Is(errType error) bool {
|
2023-01-01 14:25:00 +01:00
|
|
|
var t *SendError
|
2024-02-27 11:32:12 +01:00
|
|
|
if errors.As(errType, &t) && t != nil {
|
2023-01-01 14:25:00 +01:00
|
|
|
return e.Reason == t.Reason && e.isTemp == t.isTemp
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
2023-01-01 14:25:00 +01:00
|
|
|
return false
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
|
|
|
|
2023-01-02 12:14:14 +01:00
|
|
|
// IsTemp returns true if the delivery error is of temporary nature and can be retried
|
|
|
|
func (e *SendError) IsTemp() bool {
|
2023-11-20 18:45:35 +01:00
|
|
|
if e == nil {
|
|
|
|
return false
|
|
|
|
}
|
2023-01-02 12:14:14 +01:00
|
|
|
return e.isTemp
|
|
|
|
}
|
|
|
|
|
2023-01-01 14:20:13 +01:00
|
|
|
// String implements the Stringer interface for the SendErrReason
|
|
|
|
func (r SendErrReason) String() string {
|
|
|
|
switch r {
|
|
|
|
case ErrGetSender:
|
|
|
|
return "getting sender address"
|
|
|
|
case ErrGetRcpts:
|
|
|
|
return "getting recipient addresses"
|
|
|
|
case ErrSMTPMailFrom:
|
|
|
|
return "sending SMTP MAIL FROM command"
|
|
|
|
case ErrSMTPRcptTo:
|
|
|
|
return "sending SMTP RCPT TO command"
|
|
|
|
case ErrSMTPData:
|
|
|
|
return "sending SMTP DATA command"
|
|
|
|
case ErrSMTPDataClose:
|
|
|
|
return "closing SMTP DATA writer"
|
|
|
|
case ErrSMTPReset:
|
|
|
|
return "sending SMTP RESET command"
|
|
|
|
case ErrWriteContent:
|
|
|
|
return "sending message content"
|
|
|
|
case ErrConnCheck:
|
|
|
|
return "checking SMTP connection"
|
|
|
|
case ErrNoUnencoded:
|
|
|
|
return ErrServerNoUnencoded.Error()
|
2023-01-02 12:14:14 +01:00
|
|
|
case ErrAmbiguous:
|
|
|
|
return "ambiguous reason, check Msg.SendError for message specific reasons"
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|
|
|
|
return "unknown reason"
|
|
|
|
}
|
|
|
|
|
|
|
|
// isTempError checks the given SMTP error and returns true if the given error is of temporary nature
|
|
|
|
// and should be retried
|
2024-02-27 11:32:12 +01:00
|
|
|
func isTempError(err error) bool {
|
|
|
|
return err.Error()[0] == '4'
|
2023-01-01 14:20:13 +01:00
|
|
|
}
|