mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-14 01:42:54 +01:00
Winni Neessen
2c7ea3e532
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`
102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
// SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//go:build go1.20
|
|
// +build go1.20
|
|
|
|
package mail
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
// Send sends out the mail message
|
|
func (c *Client) Send(ml ...*Msg) (rerr error) {
|
|
if err := c.checkConn(); err != nil {
|
|
rerr = &SendError{Reason: ErrConnCheck, errlist: []error{err}, isTemp: isTempError(err)}
|
|
return
|
|
}
|
|
for _, m := range ml {
|
|
m.sendError = nil
|
|
if m.encoding == NoEncoding {
|
|
if ok, _ := c.sc.Extension("8BITMIME"); !ok {
|
|
m.sendError = &SendError{Reason: ErrNoUnencoded, isTemp: false}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
}
|
|
f, err := m.GetSender(false)
|
|
if err != nil {
|
|
m.sendError = &SendError{Reason: ErrGetSender, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
rl, err := m.GetRecipients()
|
|
if err != nil {
|
|
m.sendError = &SendError{Reason: ErrGetRcpts, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
|
|
if err := c.mail(f); err != nil {
|
|
m.sendError = &SendError{Reason: ErrSMTPMailFrom, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
if reserr := c.sc.Reset(); reserr != nil {
|
|
rerr = errors.Join(rerr, reserr)
|
|
}
|
|
continue
|
|
}
|
|
failed := false
|
|
rse := &SendError{}
|
|
rse.errlist = make([]error, 0)
|
|
rse.rcpt = make([]string, 0)
|
|
for _, r := range rl {
|
|
if err := c.rcpt(r); err != nil {
|
|
rse.Reason = ErrSMTPRcptTo
|
|
rse.errlist = append(rse.errlist, err)
|
|
rse.rcpt = append(rse.rcpt, r)
|
|
rse.isTemp = isTempError(err)
|
|
failed = true
|
|
}
|
|
}
|
|
if failed {
|
|
if reserr := c.sc.Reset(); reserr != nil {
|
|
rerr = errors.Join(rerr, reserr)
|
|
}
|
|
m.sendError = rse
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
w, err := c.sc.Data()
|
|
if err != nil {
|
|
m.sendError = &SendError{Reason: ErrSMTPData, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
_, err = m.WriteTo(w)
|
|
if err != nil {
|
|
m.sendError = &SendError{Reason: ErrWriteContent, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
m.sendError = &SendError{Reason: ErrSMTPDataClose, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
|
|
if err := c.Reset(); err != nil {
|
|
m.sendError = &SendError{Reason: ErrSMTPReset, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
continue
|
|
}
|
|
if err := c.checkConn(); err != nil {
|
|
m.sendError = &SendError{Reason: ErrConnCheck, errlist: []error{err}, isTemp: isTempError(err)}
|
|
rerr = errors.Join(rerr, m.sendError)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|