mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-14 18:02:55 +01:00
Winni Neessen
0aa24c6f3a
Implement MessageID and Msg methods in SendError to allow retrieval of the message ID and the affected message, respectively. These methods handle cases where the error or the message is nil, returning an empty string or nil as appropriate.
171 lines
4.7 KiB
Go
171 lines
4.7 KiB
Go
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package mail
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
// List of SendError reasons
|
|
const (
|
|
// ErrGetSender is returned if the Msg.GetSender method fails during a Client.Send
|
|
ErrGetSender SendErrReason = iota
|
|
|
|
// ErrGetRcpts is returned if the Msg.GetRecipients method fails during a Client.Send
|
|
ErrGetRcpts
|
|
|
|
// ErrSMTPMailFrom is returned if the Msg delivery failed when sending the MAIL FROM command
|
|
// to the sending SMTP server
|
|
ErrSMTPMailFrom
|
|
|
|
// ErrSMTPRcptTo is returned if the Msg delivery failed when sending the RCPT TO command
|
|
// to the sending SMTP server
|
|
ErrSMTPRcptTo
|
|
|
|
// ErrSMTPData is returned if the Msg delivery failed when sending the DATA command
|
|
// to the sending SMTP server
|
|
ErrSMTPData
|
|
|
|
// ErrSMTPDataClose is returned if the Msg delivery failed when trying to close the
|
|
// Client data writer
|
|
ErrSMTPDataClose
|
|
|
|
// ErrSMTPReset is returned if the Msg delivery failed when sending the RSET command
|
|
// to the sending SMTP server
|
|
ErrSMTPReset
|
|
|
|
// ErrWriteContent is returned if the Msg delivery failed when sending Msg content
|
|
// to the Client writer
|
|
ErrWriteContent
|
|
|
|
// ErrConnCheck is returned if the Msg delivery failed when checking if the SMTP
|
|
// server connection is still working
|
|
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
|
|
|
|
// ErrAmbiguous is a generalized delivery error for the SendError type that is
|
|
// returned if the exact reason for the delivery failure is ambiguous
|
|
ErrAmbiguous
|
|
)
|
|
|
|
// SendError is an error wrapper for delivery errors of the Msg
|
|
type SendError struct {
|
|
affectedMsg *Msg
|
|
errlist []error
|
|
isTemp bool
|
|
rcpt []string
|
|
Reason SendErrReason
|
|
}
|
|
|
|
// SendErrReason represents a comparable reason on why the delivery failed
|
|
type SendErrReason int
|
|
|
|
// Error implements the error interface for the SendError type
|
|
func (e *SendError) Error() string {
|
|
if e.Reason > 10 {
|
|
return "unknown reason"
|
|
}
|
|
|
|
var errMessage strings.Builder
|
|
errMessage.WriteString(e.Reason.String())
|
|
if len(e.errlist) > 0 {
|
|
errMessage.WriteRune(':')
|
|
for i := range e.errlist {
|
|
errMessage.WriteRune(' ')
|
|
errMessage.WriteString(e.errlist[i].Error())
|
|
if i != len(e.errlist)-1 {
|
|
errMessage.WriteString(", ")
|
|
}
|
|
}
|
|
}
|
|
if len(e.rcpt) > 0 {
|
|
errMessage.WriteString(", affected recipient(s): ")
|
|
for i := range e.rcpt {
|
|
errMessage.WriteString(e.rcpt[i])
|
|
if i != len(e.rcpt)-1 {
|
|
errMessage.WriteString(", ")
|
|
}
|
|
}
|
|
}
|
|
if e.affectedMsg != nil && e.affectedMsg.GetMessageID() != "" {
|
|
errMessage.WriteString(", affected message ID: ")
|
|
errMessage.WriteString(e.affectedMsg.GetMessageID())
|
|
}
|
|
|
|
return errMessage.String()
|
|
}
|
|
|
|
// Is implements the errors.Is functionality and compares the SendErrReason
|
|
func (e *SendError) Is(errType error) bool {
|
|
var t *SendError
|
|
if errors.As(errType, &t) && t != nil {
|
|
return e.Reason == t.Reason && e.isTemp == t.isTemp
|
|
}
|
|
return false
|
|
}
|
|
|
|
// IsTemp returns true if the delivery error is of temporary nature and can be retried
|
|
func (e *SendError) IsTemp() bool {
|
|
if e == nil {
|
|
return false
|
|
}
|
|
return e.isTemp
|
|
}
|
|
|
|
// MessageID returns the message ID of the affected Msg that caused the error
|
|
// If no message ID was set for the Msg, an empty string will be returned
|
|
func (e *SendError) MessageID() string {
|
|
if e == nil || e.affectedMsg == nil {
|
|
return ""
|
|
}
|
|
return e.affectedMsg.GetMessageID()
|
|
}
|
|
|
|
// Msg returns the pointer to the affected message that caused the error
|
|
func (e *SendError) Msg() *Msg {
|
|
if e == nil || e.affectedMsg == nil {
|
|
return nil
|
|
}
|
|
return e.affectedMsg
|
|
}
|
|
|
|
// 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()
|
|
case ErrAmbiguous:
|
|
return "ambiguous reason, check Msg.SendError for message specific reasons"
|
|
}
|
|
return "unknown reason"
|
|
}
|
|
|
|
// isTempError checks the given SMTP error and returns true if the given error is of temporary nature
|
|
// and should be retried
|
|
func isTempError(err error) bool {
|
|
return err.Error()[0] == '4'
|
|
}
|