mirror of
https://github.com/foxcpp/maddy.git
synced 2025-04-03 05:07:38 +03:00
146 lines
4.4 KiB
Go
146 lines
4.4 KiB
Go
/*
|
|
Maddy Mail Server - Composable all-in-one email server.
|
|
Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package exterrors
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/emersion/go-smtp"
|
|
)
|
|
|
|
type EnhancedCode smtp.EnhancedCode
|
|
|
|
func (ec EnhancedCode) FormatLog() string {
|
|
return fmt.Sprintf("%d.%d.%d", ec[0], ec[1], ec[2])
|
|
}
|
|
|
|
// SMTPError type is a copy of emersion/go-smtp.SMTPError type
|
|
// that extends it with Fields method for logging and reporting
|
|
// in maddy. It should be used instead of the go-smtp library type for all
|
|
// errors.
|
|
type SMTPError struct {
|
|
// SMTP status code. Most of these codes are overly generic and are barely
|
|
// useful. Nonetheless, take a look at the 'Associated basic status code'
|
|
// in the SMTP Enhanced Status Codes registry (below), then check RFC 5321
|
|
// (Section 4.3.2) and pick what you like. Stick to 451 and 554 if there are
|
|
// no useful codes.
|
|
Code int
|
|
|
|
// Enhanced SMTP status code. If you are unsure, take a look at
|
|
// https://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes.xhtml
|
|
EnhancedCode EnhancedCode
|
|
|
|
// Error message that should be returned to the SMTP client.
|
|
// Usually, it should be a short and generic description of the error
|
|
// that excludes any details. Especially, for checks, avoid
|
|
// mentioning the exact policy mechanism used to avoid disclosing the
|
|
// server configuration details. Don't say "DNS error during DMARC check",
|
|
// say "DNS error during policy check". Same goes for network and file I/O
|
|
// errors. ESPECIALLY, don't include any configuration variables or object
|
|
// identifiers in it.
|
|
Message string
|
|
|
|
// If the error was generated by a message check
|
|
// this field includes module name.
|
|
CheckName string
|
|
|
|
// If the error was generated by a delivery target
|
|
// this field includes module name.
|
|
TargetName string
|
|
|
|
// If the error was generated by a message modifier
|
|
// this field includes module name.
|
|
ModifierName string
|
|
|
|
// If the error was generated as a result of another
|
|
// error - this field contains the original error object.
|
|
//
|
|
// Err.Error() will be copied into the 'reason' field returned
|
|
// by the Fields method unless a different values is specified
|
|
// using the Reason field below.
|
|
Err error
|
|
|
|
// Textual explanation of the actual error reason. Defaults to the
|
|
// Err.Error() value if Err is not nil, empty string otherwise.
|
|
Reason string
|
|
|
|
Misc map[string]interface{}
|
|
}
|
|
|
|
func (se *SMTPError) Unwrap() error {
|
|
return se.Err
|
|
}
|
|
|
|
func (se *SMTPError) Fields() map[string]interface{} {
|
|
ctx := make(map[string]interface{}, len(se.Misc)+3)
|
|
for k, v := range se.Misc {
|
|
ctx[k] = v
|
|
}
|
|
ctx["smtp_code"] = se.Code
|
|
ctx["smtp_enchcode"] = se.EnhancedCode
|
|
ctx["smtp_msg"] = se.Message
|
|
if se.CheckName != "" {
|
|
ctx["check"] = se.CheckName
|
|
}
|
|
if se.TargetName != "" {
|
|
ctx["target"] = se.TargetName
|
|
}
|
|
if se.Reason != "" {
|
|
ctx["reason"] = se.Reason
|
|
} else if se.Err != nil {
|
|
ctx["reason"] = se.Err.Error()
|
|
}
|
|
return ctx
|
|
}
|
|
|
|
// Temporary reports whether
|
|
func (se *SMTPError) Temporary() bool {
|
|
return se.Code/100 == 4
|
|
}
|
|
|
|
func (se *SMTPError) Error() string {
|
|
if se.Reason != "" {
|
|
return se.Reason
|
|
}
|
|
if se.Err != nil {
|
|
return se.Err.Error()
|
|
}
|
|
return se.Message
|
|
}
|
|
|
|
// SMTPCode is a convenience function that returns one of its arguments
|
|
// depending on the result of exterrors.IsTemporary for the specified error
|
|
// object.
|
|
func SMTPCode(err error, temporaryCode, permanentCode int) int {
|
|
if IsTemporary(err) {
|
|
return temporaryCode
|
|
}
|
|
return permanentCode
|
|
}
|
|
|
|
// SMTPEnchCode is a convenience function changes the first number of the SMTP enhanced
|
|
// status code based on the value exterrors.IsTemporary returns for the specified
|
|
// error object.
|
|
func SMTPEnchCode(err error, code EnhancedCode) EnhancedCode {
|
|
if IsTemporary(err) {
|
|
code[0] = 4
|
|
}
|
|
code[0] = 5
|
|
return code
|
|
}
|